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.
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.
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]
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
38 #include <libnvpair.h>
45 #include <sys/types.h>
46 #include <sys/vfstab.h>
47 #include <sys/param.h>
48 #include <sys/systeminfo.h>
55 #include <libdevinfo.h>
59 #include <libbe_priv.h>
61 /* Private function prototypes */
62 static int update_dataset(char *, int, char *, char *, char *);
63 static int _update_vfstab(char *, char *, char *, char *, be_fs_list_data_t
*);
64 static int be_open_menu(char *, char *, FILE **, char *, boolean_t
);
65 static int be_create_menu(char *, char *, FILE **, char *);
66 static char *be_get_auto_name(char *, char *, boolean_t
);
69 * Global error printing
71 boolean_t do_print
= B_FALSE
;
76 typedef struct zone_be_name_cb_data
{
79 } zone_be_name_cb_data_t
;
81 /* ******************************************************************** */
82 /* Public Functions */
83 /* ******************************************************************** */
86 * Function: be_max_avail
87 * Description: Returns the available size for the zfs dataset passed in.
89 * dataset - The dataset we want to get the available space for.
90 * ret - The available size will be returned in this.
92 * The error returned by the zfs get property function.
97 be_max_avail(char *dataset
, uint64_t *ret
)
102 /* Initialize libzfs handle */
104 return (BE_ERR_INIT
);
106 zhp
= zfs_open(g_zfs
, dataset
, ZFS_TYPE_DATASET
);
109 * The zfs_open failed return an error
111 err
= zfs_err_to_be_err(g_zfs
);
113 err
= be_maxsize_avail(zhp
, ret
);
121 * Function: libbe_print_errors
122 * Description: Turns on/off error output for the library.
124 * set_do_print - Boolean that turns library error
125 * printing on or off.
132 libbe_print_errors(boolean_t set_do_print
)
134 do_print
= set_do_print
;
137 /* ******************************************************************** */
138 /* Semi-Private Functions */
139 /* ******************************************************************** */
142 * Function: be_zfs_init
143 * Description: Initializes the libary global libzfs handle.
150 * Semi-private (library wide use only)
157 if ((g_zfs
= libzfs_init()) == NULL
) {
158 be_print_err(gettext("be_zfs_init: failed to initialize ZFS "
167 * Function: be_zfs_fini
168 * Description: Closes the library global libzfs handle if it currently open.
174 * Semi-private (library wide use only)
186 * Function: be_get_defaults
187 * Description: Open defaults and gets be default paramets
189 * defaults - be defaults struct
193 * Semi-private (library wide use only)
196 be_get_defaults(struct be_defaults
*defaults
)
200 defaults
->be_deflt_rpool_container
= B_FALSE
;
201 defaults
->be_deflt_bename_starts_with
[0] = '\0';
203 if ((defp
= defopen_r(BE_DEFAULTS
)) != NULL
) {
204 const char *res
= defread_r(BE_DFLT_BENAME_STARTS
, defp
);
205 if (res
!= NULL
&& res
[0] != NULL
) {
206 (void) strlcpy(defaults
->be_deflt_bename_starts_with
,
207 res
, ZFS_MAXNAMELEN
);
208 defaults
->be_deflt_rpool_container
= B_TRUE
;
215 * Function: be_make_root_ds
216 * Description: Generate string for BE's root dataset given the pool
217 * it lives in and the BE name.
219 * zpool - pointer zpool name.
220 * be_name - pointer to BE name.
221 * be_root_ds - pointer to buffer to return BE root dataset in.
222 * be_root_ds_size - size of be_root_ds
226 * Semi-private (library wide use only)
229 be_make_root_ds(const char *zpool
, const char *be_name
, char *be_root_ds
,
232 struct be_defaults be_defaults
;
233 be_get_defaults(&be_defaults
);
234 char *root_ds
= NULL
;
236 if (getzoneid() == GLOBAL_ZONEID
) {
237 if (be_defaults
.be_deflt_rpool_container
) {
238 (void) snprintf(be_root_ds
, be_root_ds_size
,
239 "%s/%s", zpool
, be_name
);
241 (void) snprintf(be_root_ds
, be_root_ds_size
,
242 "%s/%s/%s", zpool
, BE_CONTAINER_DS_NAME
, be_name
);
246 * In non-global zone we can use path from mounted root dataset
247 * to generate BE's root dataset string.
249 if ((root_ds
= be_get_ds_from_dir("/")) != NULL
) {
250 (void) snprintf(be_root_ds
, be_root_ds_size
, "%s/%s",
251 dirname(root_ds
), be_name
);
253 be_print_err(gettext("be_make_root_ds: zone root "
254 "dataset is not mounted\n"));
261 * Function: be_make_container_ds
262 * Description: Generate string for the BE container dataset given a pool name.
264 * zpool - pointer zpool name.
265 * container_ds - pointer to buffer to return BE container
267 * container_ds_size - size of container_ds
271 * Semi-private (library wide use only)
274 be_make_container_ds(const char *zpool
, char *container_ds
,
275 int container_ds_size
)
277 struct be_defaults be_defaults
;
278 be_get_defaults(&be_defaults
);
279 char *root_ds
= NULL
;
281 if (getzoneid() == GLOBAL_ZONEID
) {
282 if (be_defaults
.be_deflt_rpool_container
) {
283 (void) snprintf(container_ds
, container_ds_size
,
286 (void) snprintf(container_ds
, container_ds_size
,
287 "%s/%s", zpool
, BE_CONTAINER_DS_NAME
);
290 if ((root_ds
= be_get_ds_from_dir("/")) != NULL
) {
291 (void) strlcpy(container_ds
, dirname(root_ds
),
294 be_print_err(gettext("be_make_container_ds: zone root "
295 "dataset is not mounted\n"));
302 * Function: be_make_name_from_ds
303 * Description: This function takes a dataset name and strips off the
304 * BE container dataset portion from the beginning. The
305 * returned name is allocated in heap storage, so the caller
306 * is responsible for freeing it.
308 * dataset - dataset to get name from.
309 * rc_loc - dataset underwhich the root container dataset lives.
311 * name of dataset relative to BE container dataset.
312 * NULL if dataset is not under a BE root dataset.
314 * Semi-primate (library wide use only)
317 be_make_name_from_ds(const char *dataset
, char *rc_loc
)
319 char ds
[ZFS_MAXNAMELEN
];
322 struct be_defaults be_defaults
;
323 int rlen
= strlen(rc_loc
);
325 be_get_defaults(&be_defaults
);
328 * First token is the location of where the root container dataset
329 * lives; it must match rc_loc.
331 if (strncmp(dataset
, rc_loc
, rlen
) == 0 && dataset
[rlen
] == '/')
332 (void) strlcpy(ds
, dataset
+ rlen
+ 1, sizeof (ds
));
336 if (be_defaults
.be_deflt_rpool_container
) {
337 if ((name
= strdup(ds
)) == NULL
) {
338 be_print_err(gettext("be_make_name_from_ds: "
339 "memory allocation failed\n"));
343 /* Second token must be BE container dataset name */
344 if ((tok
= strtok(ds
, "/")) == NULL
||
345 strcmp(tok
, BE_CONTAINER_DS_NAME
) != 0)
348 /* Return the remaining token if one exists */
349 if ((tok
= strtok(NULL
, "")) == NULL
)
352 if ((name
= strdup(tok
)) == NULL
) {
353 be_print_err(gettext("be_make_name_from_ds: "
354 "memory allocation failed\n"));
363 * Function: be_maxsize_avail
364 * Description: Returns the available size for the zfs handle passed in.
366 * zhp - A pointer to the open zfs handle.
367 * ret - The available size will be returned in this.
369 * The error returned by the zfs get property function.
371 * Semi-private (library wide use only)
374 be_maxsize_avail(zfs_handle_t
*zhp
, uint64_t *ret
)
376 return ((*ret
= zfs_prop_get_int(zhp
, ZFS_PROP_AVAILABLE
)));
380 * Function: be_append_menu
381 * Description: Appends an entry for a BE into the menu.lst.
383 * be_name - pointer to name of BE to add boot menu entry for.
384 * be_root_pool - pointer to name of pool BE lives in.
385 * boot_pool - Used if the pool containing the grub menu is
386 * different than the one contaiing the BE. This
387 * will normally be NULL.
388 * be_orig_root_ds - The root dataset for the BE. This is
389 * used to check to see if an entry already exists
391 * description - pointer to description of BE to be added in
392 * the title line for this BEs entry.
394 * BE_SUCCESS - Success
395 * be_errno_t - Failure
397 * Semi-private (library wide use only)
400 be_append_menu(char *be_name
, char *be_root_pool
, char *boot_pool
,
401 char *be_orig_root_ds
, char *description
)
403 zfs_handle_t
*zhp
= NULL
;
404 char menu_file
[MAXPATHLEN
];
405 char be_root_ds
[MAXPATHLEN
];
407 char temp_line
[BUFSIZ
];
408 char title
[MAXPATHLEN
];
409 char *entries
[BUFSIZ
];
410 char *tmp_entries
[BUFSIZ
];
411 char *pool_mntpnt
= NULL
;
412 char *ptmp_mntpnt
= NULL
;
413 char *orig_mntpnt
= NULL
;
414 boolean_t found_be
= B_FALSE
;
415 boolean_t found_orig_be
= B_FALSE
;
416 boolean_t found_title
= B_FALSE
;
417 boolean_t pool_mounted
= B_FALSE
;
418 boolean_t collect_lines
= B_FALSE
;
419 FILE *menu_fp
= NULL
;
420 int err
= 0, ret
= BE_SUCCESS
;
421 int i
, num_tmp_lines
= 0, num_lines
= 0;
423 if (be_name
== NULL
|| be_root_pool
== NULL
)
424 return (BE_ERR_INVAL
);
426 if (boot_pool
== NULL
)
427 boot_pool
= be_root_pool
;
429 if ((zhp
= zfs_open(g_zfs
, be_root_pool
, ZFS_TYPE_DATASET
)) == NULL
) {
430 be_print_err(gettext("be_append_menu: failed to open "
431 "pool dataset for %s: %s\n"), be_root_pool
,
432 libzfs_error_description(g_zfs
));
433 return (zfs_err_to_be_err(g_zfs
));
437 * Check to see if the pool's dataset is mounted. If it isn't we'll
438 * attempt to mount it.
440 if ((ret
= be_mount_pool(zhp
, &ptmp_mntpnt
, &orig_mntpnt
,
441 &pool_mounted
)) != BE_SUCCESS
) {
442 be_print_err(gettext("be_append_menu: pool dataset "
443 "(%s) could not be mounted\n"), be_root_pool
);
449 * Get the mountpoint for the root pool dataset.
451 if (!zfs_is_mounted(zhp
, &pool_mntpnt
)) {
452 be_print_err(gettext("be_append_menu: pool "
453 "dataset (%s) is not mounted. Can't set "
454 "the default BE in the grub menu.\n"), be_root_pool
);
455 ret
= BE_ERR_NO_MENU
;
460 * Check to see if this system supports grub
463 (void) snprintf(menu_file
, sizeof (menu_file
),
464 "%s%s", pool_mntpnt
, BE_GRUB_MENU
);
466 (void) snprintf(menu_file
, sizeof (menu_file
),
467 "%s%s", pool_mntpnt
, BE_SPARC_MENU
);
470 be_make_root_ds(be_root_pool
, be_name
, be_root_ds
, sizeof (be_root_ds
));
473 * Iterate through menu first to make sure the BE doesn't already
474 * have an entry in the menu.
476 * Additionally while iterating through the menu, if we have an
477 * original root dataset for a BE we're cloning from, we need to keep
478 * track of that BE's menu entry. We will then use the lines from
479 * that entry to create the entry for the new BE.
481 if ((ret
= be_open_menu(be_root_pool
, menu_file
,
482 &menu_fp
, "r", B_TRUE
)) != BE_SUCCESS
) {
484 } else if (menu_fp
== NULL
) {
485 ret
= BE_ERR_NO_MENU
;
492 while (fgets(line
, BUFSIZ
, menu_fp
)) {
495 (void) strlcpy(temp_line
, line
, BUFSIZ
);
496 tok
= strtok(line
, BE_WHITE_SPACE
);
498 if (tok
== NULL
|| tok
[0] == '#') {
500 } else if (strcmp(tok
, "title") == 0) {
501 collect_lines
= B_FALSE
;
502 if ((tok
= strtok(NULL
, "\n")) == NULL
)
503 (void) strlcpy(title
, "", sizeof (title
));
505 (void) strlcpy(title
, tok
, sizeof (title
));
506 found_title
= B_TRUE
;
508 if (num_tmp_lines
!= 0) {
509 for (i
= 0; i
< num_tmp_lines
; i
++) {
510 free(tmp_entries
[i
]);
511 tmp_entries
[i
] = NULL
;
515 } else if (strcmp(tok
, "bootfs") == 0) {
516 char *bootfs
= strtok(NULL
, BE_WHITE_SPACE
);
517 found_title
= B_FALSE
;
521 if (strcmp(bootfs
, be_root_ds
) == 0) {
526 if (be_orig_root_ds
!= NULL
&&
527 strcmp(bootfs
, be_orig_root_ds
) == 0 &&
530 found_orig_be
= B_TRUE
;
533 * Store the new title line
535 (void) snprintf(str
, BUFSIZ
, "title %s\n",
536 description
? description
: be_name
);
537 entries
[num_lines
] = strdup(str
);
540 * If there are any lines between the title
541 * and the bootfs line store these. Also
542 * free the temporary lines.
544 for (i
= 0; i
< num_tmp_lines
; i
++) {
545 entries
[num_lines
] = tmp_entries
[i
];
546 tmp_entries
[i
] = NULL
;
551 * Store the new bootfs line.
553 (void) snprintf(str
, BUFSIZ
, "bootfs %s\n",
555 entries
[num_lines
] = strdup(str
);
557 collect_lines
= B_TRUE
;
559 } else if (found_orig_be
&& collect_lines
) {
561 * get the rest of the lines for the original BE and
564 if (strstr(line
, BE_GRUB_COMMENT
) != NULL
||
565 strstr(line
, "BOOTADM") != NULL
)
567 if (strcmp(tok
, "splashimage") == 0) {
569 strdup("splashimage "
570 "/boot/splashimage.xpm\n");
572 entries
[num_lines
] = strdup(temp_line
);
575 } else if (found_title
&& !found_orig_be
) {
576 tmp_entries
[num_tmp_lines
] = strdup(temp_line
);
581 (void) fclose(menu_fp
);
585 * If an entry for this BE was already in the menu, then if
586 * that entry's title matches what we would have put in
587 * return success. Otherwise return failure.
589 char *new_title
= description
? description
: be_name
;
591 if (strcmp(title
, new_title
) == 0) {
595 if (be_remove_menu(be_name
, be_root_pool
,
596 boot_pool
) != BE_SUCCESS
) {
597 be_print_err(gettext("be_append_menu: "
598 "Failed to remove existing unusable "
599 "entry '%s' in boot menu.\n"), be_name
);
600 ret
= BE_ERR_BE_EXISTS
;
606 /* Append BE entry to the end of the file */
607 menu_fp
= fopen(menu_file
, "a+");
609 if (menu_fp
== NULL
) {
610 be_print_err(gettext("be_append_menu: failed "
611 "to open menu.lst file %s\n"), menu_file
);
612 ret
= errno_to_be_err(err
);
618 * write out all the stored lines
620 for (i
= 0; i
< num_lines
; i
++) {
621 (void) fprintf(menu_fp
, "%s", entries
[i
]);
627 * Check to see if this system supports grub
630 (void) fprintf(menu_fp
, "%s\n", BE_GRUB_COMMENT
);
633 (void) fprintf(menu_fp
, "title %s\n",
634 description
? description
: be_name
);
635 (void) fprintf(menu_fp
, "bootfs %s\n", be_root_ds
);
638 * Check to see if this system supports grub
641 (void) fprintf(menu_fp
, "kernel$ "
642 "/platform/i86pc/kernel/$ISADIR/unix -B "
644 (void) fprintf(menu_fp
, "module$ "
645 "/platform/i86pc/$ISADIR/boot_archive\n");
646 (void) fprintf(menu_fp
, "%s\n", BE_GRUB_COMMENT
);
650 (void) fclose(menu_fp
);
653 int err
= BE_SUCCESS
;
654 err
= be_unmount_pool(zhp
, ptmp_mntpnt
, orig_mntpnt
);
655 if (ret
== BE_SUCCESS
)
661 if (num_tmp_lines
> 0) {
662 for (i
= 0; i
< num_tmp_lines
; i
++) {
663 free(tmp_entries
[i
]);
664 tmp_entries
[i
] = NULL
;
668 for (i
= 0; i
< num_lines
; i
++) {
677 * Function: be_remove_menu
678 * Description: Removes a BE's entry from a menu.lst file.
680 * be_name - the name of BE whose entry is to be removed from
682 * be_root_pool - the pool that be_name lives in.
683 * boot_pool - the pool where the BE is, if different than
684 * the pool containing the boot menu. If this is
685 * NULL it will be set to be_root_pool.
687 * BE_SUCCESS - Success
688 * be_errno_t - Failure
690 * Semi-private (library wide use only)
693 be_remove_menu(char *be_name
, char *be_root_pool
, char *boot_pool
)
695 zfs_handle_t
*zhp
= NULL
;
696 char be_root_ds
[MAXPATHLEN
];
697 char **buffer
= NULL
;
698 char menu_buf
[BUFSIZ
];
699 char menu
[MAXPATHLEN
];
700 char *pool_mntpnt
= NULL
;
701 char *ptmp_mntpnt
= NULL
;
702 char *orig_mntpnt
= NULL
;
703 char *tmp_menu
= NULL
;
704 FILE *menu_fp
= NULL
;
705 FILE *tmp_menu_fp
= NULL
;
707 int ret
= BE_SUCCESS
;
712 int default_entry
= 0;
715 int num_entry_del
= 0;
716 int tmp_menu_len
= 0;
717 boolean_t write
= B_TRUE
;
718 boolean_t do_buffer
= B_FALSE
;
719 boolean_t pool_mounted
= B_FALSE
;
721 if (boot_pool
== NULL
)
722 boot_pool
= be_root_pool
;
724 /* Get name of BE's root dataset */
725 be_make_root_ds(be_root_pool
, be_name
, be_root_ds
, sizeof (be_root_ds
));
727 /* Get handle to pool dataset */
728 if ((zhp
= zfs_open(g_zfs
, be_root_pool
, ZFS_TYPE_DATASET
)) == NULL
) {
729 be_print_err(gettext("be_remove_menu: "
730 "failed to open pool dataset for %s: %s"),
731 be_root_pool
, libzfs_error_description(g_zfs
));
732 return (zfs_err_to_be_err(g_zfs
));
736 * Check to see if the pool's dataset is mounted. If it isn't we'll
737 * attempt to mount it.
739 if ((ret
= be_mount_pool(zhp
, &ptmp_mntpnt
, &orig_mntpnt
,
740 &pool_mounted
)) != BE_SUCCESS
) {
741 be_print_err(gettext("be_remove_menu: pool dataset "
742 "(%s) could not be mounted\n"), be_root_pool
);
748 * Get the mountpoint for the root pool dataset.
750 if (!zfs_is_mounted(zhp
, &pool_mntpnt
)) {
751 be_print_err(gettext("be_remove_menu: pool "
752 "dataset (%s) is not mounted. Can't set "
753 "the default BE in the grub menu.\n"), be_root_pool
);
754 ret
= BE_ERR_NO_MENU
;
758 /* Get path to boot menu */
759 (void) strlcpy(menu
, pool_mntpnt
, sizeof (menu
));
762 * Check to see if this system supports grub
765 (void) strlcat(menu
, BE_GRUB_MENU
, sizeof (menu
));
767 (void) strlcat(menu
, BE_SPARC_MENU
, sizeof (menu
));
769 /* Get handle to boot menu file */
770 if ((ret
= be_open_menu(be_root_pool
, menu
, &menu_fp
, "r",
771 B_TRUE
)) != BE_SUCCESS
) {
773 } else if (menu_fp
== NULL
) {
774 ret
= BE_ERR_NO_MENU
;
781 /* Grab the stats of the original menu file */
782 if (stat(menu
, &sb
) != 0) {
784 be_print_err(gettext("be_remove_menu: "
785 "failed to stat file %s: %s\n"), menu
, strerror(err
));
786 ret
= errno_to_be_err(err
);
790 /* Create a tmp file for the modified menu.lst */
791 tmp_menu_len
= strlen(menu
) + 7;
792 if ((tmp_menu
= (char *)malloc(tmp_menu_len
)) == NULL
) {
793 be_print_err(gettext("be_remove_menu: malloc failed\n"));
797 (void) memset(tmp_menu
, 0, tmp_menu_len
);
798 (void) strlcpy(tmp_menu
, menu
, tmp_menu_len
);
799 (void) strlcat(tmp_menu
, "XXXXXX", tmp_menu_len
);
800 if ((fd
= mkstemp(tmp_menu
)) == -1) {
802 be_print_err(gettext("be_remove_menu: mkstemp failed\n"));
803 ret
= errno_to_be_err(err
);
808 if ((tmp_menu_fp
= fdopen(fd
, "w")) == NULL
) {
810 be_print_err(gettext("be_remove_menu: "
811 "could not open tmp file for write: %s\n"), strerror(err
));
813 ret
= errno_to_be_err(err
);
817 while (fgets(menu_buf
, BUFSIZ
, menu_fp
)) {
821 (void) strlcpy(tline
, menu_buf
, sizeof (tline
));
824 tok
= strtok(tline
, BE_WHITE_SPACE
);
826 if (tok
== NULL
|| tok
[0] == '#') {
827 /* Found empty line or comment line */
829 /* Buffer this line */
830 if ((buffer
= (char **)realloc(buffer
,
831 sizeof (char *)*(nlines
+ 1))) == NULL
) {
835 if ((buffer
[nlines
++] = strdup(menu_buf
))
841 } else if (write
|| strncmp(menu_buf
, BE_GRUB_COMMENT
,
842 strlen(BE_GRUB_COMMENT
)) != 0) {
843 /* Write this line out */
844 (void) fputs(menu_buf
, tmp_menu_fp
);
846 } else if (strcmp(tok
, "default") == 0) {
848 * Record what 'default' is set to because we might
849 * need to adjust this upon deleting an entry.
851 tok
= strtok(NULL
, BE_WHITE_SPACE
);
854 default_entry
= atoi(tok
);
857 (void) fputs(menu_buf
, tmp_menu_fp
);
858 } else if (strcmp(tok
, "title") == 0) {
860 * If we've reached a 'title' line and do_buffer is
861 * is true, that means we've just buffered an entire
862 * entry without finding a 'bootfs' directive. We
863 * need to write that entry out and keep searching.
866 for (i
= 0; i
< nlines
; i
++) {
867 (void) fputs(buffer
[i
], tmp_menu_fp
);
876 * Turn writing off and buffering on, and increment
883 /* Buffer this 'title' line */
884 if ((buffer
= (char **)realloc(buffer
,
885 sizeof (char *)*(nlines
+ 1))) == NULL
) {
889 if ((buffer
[nlines
++] = strdup(menu_buf
)) == NULL
) {
894 } else if (strcmp(tok
, "bootfs") == 0) {
898 * Found a 'bootfs' line. See if it matches the
899 * BE we're looking for.
901 if ((bootfs
= strtok(NULL
, BE_WHITE_SPACE
)) == NULL
||
902 strcmp(bootfs
, be_root_ds
) != 0) {
904 * Either there's nothing after the 'bootfs'
905 * or this is not the BE we're looking for,
906 * write out the line(s) we've buffered since
909 for (i
= 0; i
< nlines
; i
++) {
910 (void) fputs(buffer
[i
], tmp_menu_fp
);
918 * Turn writing back on, and turn off buffering
919 * since this isn't the entry we're looking
925 /* Write this 'bootfs' line out. */
926 (void) fputs(menu_buf
, tmp_menu_fp
);
929 * Found the entry we're looking for.
930 * Record its entry number, increment the
931 * number of entries we've deleted, and turn
932 * writing off. Also, throw away the lines
933 * we've buffered for this entry so far, we
936 entry_del
= entry_cnt
- 1;
941 for (i
= 0; i
< nlines
; i
++) {
950 /* Buffer this line */
951 if ((buffer
= (char **)realloc(buffer
,
952 sizeof (char *)*(nlines
+ 1))) == NULL
) {
956 if ((buffer
[nlines
++] = strdup(menu_buf
))
962 /* Write this line out */
963 (void) fputs(menu_buf
, tmp_menu_fp
);
968 (void) fclose(menu_fp
);
970 (void) fclose(tmp_menu_fp
);
973 /* Copy the modified menu.lst into place */
974 if (rename(tmp_menu
, menu
) != 0) {
976 be_print_err(gettext("be_remove_menu: "
977 "failed to rename file %s to %s: %s\n"),
978 tmp_menu
, menu
, strerror(err
));
979 ret
= errno_to_be_err(err
);
986 * If we've removed an entry, see if we need to
987 * adjust the default value in the menu.lst. If the
988 * entry we've deleted comes before the default entry
989 * we need to adjust the default value accordingly.
991 * be_has_grub is used here to check to see if this system
994 if (be_has_grub() && num_entry_del
> 0) {
995 if (entry_del
<= default_entry
) {
996 default_entry
= default_entry
- num_entry_del
;
997 if (default_entry
< 0)
1001 * Adjust the default value by rewriting the
1002 * menu.lst file. This may be overkill, but to
1003 * preserve the location of the 'default' entry
1004 * in the file, we need to do this.
1007 /* Get handle to boot menu file */
1008 if ((menu_fp
= fopen(menu
, "r")) == NULL
) {
1010 be_print_err(gettext("be_remove_menu: "
1011 "failed to open menu.lst (%s): %s\n"),
1012 menu
, strerror(err
));
1013 ret
= errno_to_be_err(err
);
1017 /* Create a tmp file for the modified menu.lst */
1018 tmp_menu_len
= strlen(menu
) + 7;
1019 if ((tmp_menu
= (char *)malloc(tmp_menu_len
))
1021 be_print_err(gettext("be_remove_menu: "
1022 "malloc failed\n"));
1026 (void) memset(tmp_menu
, 0, tmp_menu_len
);
1027 (void) strlcpy(tmp_menu
, menu
, tmp_menu_len
);
1028 (void) strlcat(tmp_menu
, "XXXXXX", tmp_menu_len
);
1029 if ((fd
= mkstemp(tmp_menu
)) == -1) {
1031 be_print_err(gettext("be_remove_menu: "
1032 "mkstemp failed: %s\n"), strerror(err
));
1033 ret
= errno_to_be_err(err
);
1038 if ((tmp_menu_fp
= fdopen(fd
, "w")) == NULL
) {
1040 be_print_err(gettext("be_remove_menu: "
1041 "could not open tmp file for write: %s\n"),
1044 ret
= errno_to_be_err(err
);
1048 while (fgets(menu_buf
, BUFSIZ
, menu_fp
)) {
1049 char tline
[BUFSIZ
];
1052 (void) strlcpy(tline
, menu_buf
, sizeof (tline
));
1055 tok
= strtok(tline
, BE_WHITE_SPACE
);
1058 /* Found empty line, write it out */
1059 (void) fputs(menu_buf
, tmp_menu_fp
);
1060 } else if (strcmp(tok
, "default") == 0) {
1061 /* Found the default line, adjust it */
1062 (void) snprintf(tline
, sizeof (tline
),
1063 "default %d\n", default_entry
);
1065 (void) fputs(tline
, tmp_menu_fp
);
1067 /* Pass through all other lines */
1068 (void) fputs(menu_buf
, tmp_menu_fp
);
1072 (void) fclose(menu_fp
);
1074 (void) fclose(tmp_menu_fp
);
1077 /* Copy the modified menu.lst into place */
1078 if (rename(tmp_menu
, menu
) != 0) {
1080 be_print_err(gettext("be_remove_menu: "
1081 "failed to rename file %s to %s: %s\n"),
1082 tmp_menu
, menu
, strerror(err
));
1083 ret
= errno_to_be_err(err
);
1092 /* Set the perms and ownership of the updated file */
1093 if (chmod(menu
, sb
.st_mode
) != 0) {
1095 be_print_err(gettext("be_remove_menu: "
1096 "failed to chmod %s: %s\n"), menu
, strerror(err
));
1097 ret
= errno_to_be_err(err
);
1100 if (chown(menu
, sb
.st_uid
, sb
.st_gid
) != 0) {
1102 be_print_err(gettext("be_remove_menu: "
1103 "failed to chown %s: %s\n"), menu
, strerror(err
));
1104 ret
= errno_to_be_err(err
);
1110 int err
= BE_SUCCESS
;
1111 err
= be_unmount_pool(zhp
, ptmp_mntpnt
, orig_mntpnt
);
1112 if (ret
== BE_SUCCESS
)
1120 if (menu_fp
!= NULL
)
1121 (void) fclose(menu_fp
);
1122 if (tmp_menu_fp
!= NULL
)
1123 (void) fclose(tmp_menu_fp
);
1124 if (tmp_menu
!= NULL
) {
1125 (void) unlink(tmp_menu
);
1133 * Function: be_default_grub_bootfs
1134 * Description: This function returns the dataset in the default entry of
1135 * the grub menu. If no default entry is found with a valid bootfs
1136 * entry NULL is returned.
1138 * be_root_pool - This is the name of the root pool where the
1139 * grub menu can be found.
1140 * def_bootfs - This is used to pass back the bootfs string. On
1141 * error NULL is returned here.
1143 * Success - BE_SUCCESS is returned.
1144 * Failure - a be_errno_t is returned.
1146 * Semi-private (library wide use only)
1149 be_default_grub_bootfs(const char *be_root_pool
, char **def_bootfs
)
1151 zfs_handle_t
*zhp
= NULL
;
1152 char grub_file
[MAXPATHLEN
];
1155 char *pool_mntpnt
= NULL
;
1156 char *ptmp_mntpnt
= NULL
;
1157 char *orig_mntpnt
= NULL
;
1158 int default_entry
= 0, entries
= 0;
1159 int found_default
= 0;
1160 int ret
= BE_SUCCESS
;
1161 boolean_t pool_mounted
= B_FALSE
;
1166 * Check to see if this system supports grub
1168 if (!be_has_grub()) {
1169 be_print_err(gettext("be_default_grub_bootfs: operation "
1170 "not supported on this architecture\n"));
1171 return (BE_ERR_NOTSUP
);
1176 /* Get handle to pool dataset */
1177 if ((zhp
= zfs_open(g_zfs
, be_root_pool
, ZFS_TYPE_DATASET
)) == NULL
) {
1178 be_print_err(gettext("be_default_grub_bootfs: "
1179 "failed to open pool dataset for %s: %s"),
1180 be_root_pool
, libzfs_error_description(g_zfs
));
1181 return (zfs_err_to_be_err(g_zfs
));
1185 * Check to see if the pool's dataset is mounted. If it isn't we'll
1186 * attempt to mount it.
1188 if ((ret
= be_mount_pool(zhp
, &ptmp_mntpnt
, &orig_mntpnt
,
1189 &pool_mounted
)) != BE_SUCCESS
) {
1190 be_print_err(gettext("be_default_grub_bootfs: pool dataset "
1191 "(%s) could not be mounted\n"), be_root_pool
);
1197 * Get the mountpoint for the root pool dataset.
1199 if (!zfs_is_mounted(zhp
, &pool_mntpnt
)) {
1200 be_print_err(gettext("be_default_grub_bootfs: failed "
1201 "to get mount point for the root pool. Can't set "
1202 "the default BE in the grub menu.\n"));
1203 ret
= BE_ERR_NO_MENU
;
1207 (void) snprintf(grub_file
, MAXPATHLEN
, "%s%s",
1208 pool_mntpnt
, BE_GRUB_MENU
);
1210 if ((ret
= be_open_menu((char *)be_root_pool
, grub_file
,
1211 &menu_fp
, "r", B_FALSE
)) != BE_SUCCESS
) {
1213 } else if (menu_fp
== NULL
) {
1214 ret
= BE_ERR_NO_MENU
;
1221 while (fgets(line
, BUFSIZ
, menu_fp
)) {
1222 char *tok
= strtok(line
, BE_WHITE_SPACE
);
1224 if (tok
!= NULL
&& tok
[0] != '#') {
1225 if (!found_default
) {
1226 if (strcmp(tok
, "default") == 0) {
1227 tok
= strtok(NULL
, BE_WHITE_SPACE
);
1229 default_entry
= atoi(tok
);
1236 if (strcmp(tok
, "title") == 0) {
1238 } else if (default_entry
== entries
- 1) {
1239 if (strcmp(tok
, "bootfs") == 0) {
1240 tok
= strtok(NULL
, BE_WHITE_SPACE
);
1241 (void) fclose(menu_fp
);
1248 if ((*def_bootfs
= strdup(tok
)) !=
1253 be_print_err(gettext(
1254 "be_default_grub_bootfs: "
1255 "memory allocation failed\n"));
1259 } else if (default_entry
< entries
- 1) {
1261 * no bootfs entry for the default entry.
1267 (void) fclose(menu_fp
);
1271 int err
= BE_SUCCESS
;
1272 err
= be_unmount_pool(zhp
, ptmp_mntpnt
, orig_mntpnt
);
1273 if (ret
== BE_SUCCESS
)
1283 * Function: be_change_grub_default
1284 * Description: This function takes two parameters. These are the name of
1285 * the BE we want to have as the default booted in the grub
1286 * menu and the root pool where the path to the grub menu exists.
1287 * The code takes this and finds the BE's entry in the grub menu
1288 * and changes the default entry to point to that entry in the
1291 * be_name - This is the name of the BE wanted as the default
1292 * for the next boot.
1293 * be_root_pool - This is the name of the root pool where the
1294 * grub menu can be found.
1296 * BE_SUCCESS - Success
1297 * be_errno_t - Failure
1299 * Semi-private (library wide use only)
1302 be_change_grub_default(char *be_name
, char *be_root_pool
)
1304 zfs_handle_t
*zhp
= NULL
;
1305 char grub_file
[MAXPATHLEN
];
1307 char *pool_mntpnt
= NULL
;
1308 char *ptmp_mntpnt
= NULL
;
1309 char *orig_mntpnt
= NULL
;
1311 char temp_line
[BUFSIZ
];
1312 char be_root_ds
[MAXPATHLEN
];
1313 FILE *grub_fp
= NULL
;
1314 FILE *temp_fp
= NULL
;
1316 int temp_grub_len
= 0;
1317 int fd
, entries
= 0;
1319 int ret
= BE_SUCCESS
;
1320 boolean_t found_default
= B_FALSE
;
1321 boolean_t pool_mounted
= B_FALSE
;
1326 * Check to see if this system supports grub
1328 if (!be_has_grub()) {
1329 be_print_err(gettext("be_change_grub_default: operation "
1330 "not supported on this architecture\n"));
1331 return (BE_ERR_NOTSUP
);
1334 /* Generate string for BE's root dataset */
1335 be_make_root_ds(be_root_pool
, be_name
, be_root_ds
, sizeof (be_root_ds
));
1337 /* Get handle to pool dataset */
1338 if ((zhp
= zfs_open(g_zfs
, be_root_pool
, ZFS_TYPE_DATASET
)) == NULL
) {
1339 be_print_err(gettext("be_change_grub_default: "
1340 "failed to open pool dataset for %s: %s"),
1341 be_root_pool
, libzfs_error_description(g_zfs
));
1342 return (zfs_err_to_be_err(g_zfs
));
1346 * Check to see if the pool's dataset is mounted. If it isn't we'll
1347 * attempt to mount it.
1349 if ((ret
= be_mount_pool(zhp
, &ptmp_mntpnt
, &orig_mntpnt
,
1350 &pool_mounted
)) != BE_SUCCESS
) {
1351 be_print_err(gettext("be_change_grub_default: pool dataset "
1352 "(%s) could not be mounted\n"), be_root_pool
);
1358 * Get the mountpoint for the root pool dataset.
1360 if (!zfs_is_mounted(zhp
, &pool_mntpnt
)) {
1361 be_print_err(gettext("be_change_grub_default: pool "
1362 "dataset (%s) is not mounted. Can't set "
1363 "the default BE in the grub menu.\n"), be_root_pool
);
1364 ret
= BE_ERR_NO_MENU
;
1368 (void) snprintf(grub_file
, MAXPATHLEN
, "%s%s",
1369 pool_mntpnt
, BE_GRUB_MENU
);
1371 if ((ret
= be_open_menu(be_root_pool
, grub_file
,
1372 &grub_fp
, "r+", B_TRUE
)) != BE_SUCCESS
) {
1374 } else if (grub_fp
== NULL
) {
1375 ret
= BE_ERR_NO_MENU
;
1382 /* Grab the stats of the original menu file */
1383 if (stat(grub_file
, &sb
) != 0) {
1385 be_print_err(gettext("be_change_grub_default: "
1386 "failed to stat file %s: %s\n"), grub_file
, strerror(err
));
1387 ret
= errno_to_be_err(err
);
1391 /* Create a tmp file for the modified menu.lst */
1392 temp_grub_len
= strlen(grub_file
) + 7;
1393 if ((temp_grub
= (char *)malloc(temp_grub_len
)) == NULL
) {
1394 be_print_err(gettext("be_change_grub_default: "
1395 "malloc failed\n"));
1399 (void) memset(temp_grub
, 0, temp_grub_len
);
1400 (void) strlcpy(temp_grub
, grub_file
, temp_grub_len
);
1401 (void) strlcat(temp_grub
, "XXXXXX", temp_grub_len
);
1402 if ((fd
= mkstemp(temp_grub
)) == -1) {
1404 be_print_err(gettext("be_change_grub_default: "
1405 "mkstemp failed: %s\n"), strerror(err
));
1406 ret
= errno_to_be_err(err
);
1411 if ((temp_fp
= fdopen(fd
, "w")) == NULL
) {
1413 be_print_err(gettext("be_change_grub_default: "
1414 "failed to open %s file: %s\n"),
1415 temp_grub
, strerror(err
));
1417 ret
= errno_to_be_err(err
);
1421 while (fgets(line
, BUFSIZ
, grub_fp
)) {
1422 char *tok
= strtok(line
, BE_WHITE_SPACE
);
1424 if (tok
== NULL
|| tok
[0] == '#') {
1426 } else if (strcmp(tok
, "title") == 0) {
1429 } else if (strcmp(tok
, "bootfs") == 0) {
1430 char *bootfs
= strtok(NULL
, BE_WHITE_SPACE
);
1434 if (strcmp(bootfs
, be_root_ds
) == 0) {
1435 found_default
= B_TRUE
;
1441 if (!found_default
) {
1442 be_print_err(gettext("be_change_grub_default: failed "
1443 "to find entry for %s in the grub menu\n"),
1445 ret
= BE_ERR_BE_NOENT
;
1451 while (fgets(line
, BUFSIZ
, grub_fp
)) {
1454 (void) strncpy(temp_line
, line
, BUFSIZ
);
1456 if ((tok
= strtok(temp_line
, BE_WHITE_SPACE
)) != NULL
&&
1457 strcmp(tok
, "default") == 0) {
1458 (void) snprintf(temp_line
, BUFSIZ
, "default %d\n",
1459 entries
- 1 >= 0 ? entries
- 1 : 0);
1460 (void) fputs(temp_line
, temp_fp
);
1462 (void) fputs(line
, temp_fp
);
1466 (void) fclose(grub_fp
);
1468 (void) fclose(temp_fp
);
1471 if (rename(temp_grub
, grub_file
) != 0) {
1473 be_print_err(gettext("be_change_grub_default: "
1474 "failed to rename file %s to %s: %s\n"),
1475 temp_grub
, grub_file
, strerror(err
));
1476 ret
= errno_to_be_err(err
);
1482 /* Set the perms and ownership of the updated file */
1483 if (chmod(grub_file
, sb
.st_mode
) != 0) {
1485 be_print_err(gettext("be_change_grub_default: "
1486 "failed to chmod %s: %s\n"), grub_file
, strerror(err
));
1487 ret
= errno_to_be_err(err
);
1490 if (chown(grub_file
, sb
.st_uid
, sb
.st_gid
) != 0) {
1492 be_print_err(gettext("be_change_grub_default: "
1493 "failed to chown %s: %s\n"), grub_file
, strerror(err
));
1494 ret
= errno_to_be_err(err
);
1499 int err
= BE_SUCCESS
;
1500 err
= be_unmount_pool(zhp
, ptmp_mntpnt
, orig_mntpnt
);
1501 if (ret
== BE_SUCCESS
)
1507 if (grub_fp
!= NULL
)
1508 (void) fclose(grub_fp
);
1509 if (temp_fp
!= NULL
)
1510 (void) fclose(temp_fp
);
1511 if (temp_grub
!= NULL
) {
1512 (void) unlink(temp_grub
);
1520 * Function: be_update_menu
1521 * Description: This function is used by be_rename to change the BE name in
1522 * an existing entry in the grub menu to the new name of the BE.
1524 * be_orig_name - the original name of the BE
1525 * be_new_name - the new name the BE is being renameed to.
1526 * be_root_pool - The pool which contains the grub menu
1527 * boot_pool - the pool where the BE is, if different than
1528 * the pool containing the boot menu. If this is
1529 * NULL it will be set to be_root_pool.
1531 * BE_SUCCESS - Success
1532 * be_errno_t - Failure
1534 * Semi-private (library wide use only)
1537 be_update_menu(char *be_orig_name
, char *be_new_name
, char *be_root_pool
,
1540 zfs_handle_t
*zhp
= NULL
;
1541 char menu_file
[MAXPATHLEN
];
1542 char be_root_ds
[MAXPATHLEN
];
1543 char be_new_root_ds
[MAXPATHLEN
];
1545 char *pool_mntpnt
= NULL
;
1546 char *ptmp_mntpnt
= NULL
;
1547 char *orig_mntpnt
= NULL
;
1548 char *temp_menu
= NULL
;
1549 FILE *menu_fp
= NULL
;
1550 FILE *new_fp
= NULL
;
1552 int temp_menu_len
= 0;
1554 int ret
= BE_SUCCESS
;
1556 boolean_t pool_mounted
= B_FALSE
;
1560 if (boot_pool
== NULL
)
1561 boot_pool
= be_root_pool
;
1563 if ((zhp
= zfs_open(g_zfs
, be_root_pool
, ZFS_TYPE_DATASET
)) == NULL
) {
1564 be_print_err(gettext("be_update_menu: failed to open "
1565 "pool dataset for %s: %s\n"), be_root_pool
,
1566 libzfs_error_description(g_zfs
));
1567 return (zfs_err_to_be_err(g_zfs
));
1571 * Check to see if the pool's dataset is mounted. If it isn't we'll
1572 * attempt to mount it.
1574 if ((ret
= be_mount_pool(zhp
, &ptmp_mntpnt
, &orig_mntpnt
,
1575 &pool_mounted
)) != BE_SUCCESS
) {
1576 be_print_err(gettext("be_update_menu: pool dataset "
1577 "(%s) could not be mounted\n"), be_root_pool
);
1583 * Get the mountpoint for the root pool dataset.
1585 if (!zfs_is_mounted(zhp
, &pool_mntpnt
)) {
1586 be_print_err(gettext("be_update_menu: failed "
1587 "to get mount point for the root pool. Can't set "
1588 "the default BE in the grub menu.\n"));
1589 ret
= BE_ERR_NO_MENU
;
1594 * Check to see if this system supports grub
1596 if (be_has_grub()) {
1597 (void) snprintf(menu_file
, sizeof (menu_file
),
1598 "%s%s", pool_mntpnt
, BE_GRUB_MENU
);
1600 (void) snprintf(menu_file
, sizeof (menu_file
),
1601 "%s%s", pool_mntpnt
, BE_SPARC_MENU
);
1604 be_make_root_ds(be_root_pool
, be_orig_name
, be_root_ds
,
1605 sizeof (be_root_ds
));
1606 be_make_root_ds(be_root_pool
, be_new_name
, be_new_root_ds
,
1607 sizeof (be_new_root_ds
));
1609 if ((ret
= be_open_menu(be_root_pool
, menu_file
,
1610 &menu_fp
, "r", B_TRUE
)) != BE_SUCCESS
) {
1612 } else if (menu_fp
== NULL
) {
1613 ret
= BE_ERR_NO_MENU
;
1620 /* Grab the stat of the original menu file */
1621 if (stat(menu_file
, &sb
) != 0) {
1623 be_print_err(gettext("be_update_menu: "
1624 "failed to stat file %s: %s\n"), menu_file
, strerror(err
));
1625 (void) fclose(menu_fp
);
1626 ret
= errno_to_be_err(err
);
1630 /* Create tmp file for modified menu.lst */
1631 temp_menu_len
= strlen(menu_file
) + 7;
1632 if ((temp_menu
= (char *)malloc(temp_menu_len
))
1634 be_print_err(gettext("be_update_menu: "
1635 "malloc failed\n"));
1636 (void) fclose(menu_fp
);
1640 (void) memset(temp_menu
, 0, temp_menu_len
);
1641 (void) strlcpy(temp_menu
, menu_file
, temp_menu_len
);
1642 (void) strlcat(temp_menu
, "XXXXXX", temp_menu_len
);
1643 if ((tmp_fd
= mkstemp(temp_menu
)) == -1) {
1645 be_print_err(gettext("be_update_menu: "
1646 "mkstemp failed: %s\n"), strerror(err
));
1647 (void) fclose(menu_fp
);
1649 ret
= errno_to_be_err(err
);
1652 if ((new_fp
= fdopen(tmp_fd
, "w")) == NULL
) {
1654 be_print_err(gettext("be_update_menu: "
1655 "fdopen failed: %s\n"), strerror(err
));
1656 (void) close(tmp_fd
);
1657 (void) fclose(menu_fp
);
1659 ret
= errno_to_be_err(err
);
1663 while (fgets(line
, BUFSIZ
, menu_fp
)) {
1665 char new_line
[BUFSIZ
];
1668 (void) strlcpy(tline
, line
, sizeof (tline
));
1671 c
= strtok(tline
, BE_WHITE_SPACE
);
1674 /* Found empty line, write it out. */
1675 (void) fputs(line
, new_fp
);
1676 } else if (c
[0] == '#') {
1677 /* Found a comment line, write it out. */
1678 (void) fputs(line
, new_fp
);
1679 } else if (strcmp(c
, "title") == 0) {
1684 * Found a 'title' line, parse out BE name or
1687 name
= strtok(NULL
, BE_WHITE_SPACE
);
1691 * Nothing after 'title', just push
1694 (void) fputs(line
, new_fp
);
1697 * Grab the remainder of the title which
1698 * could be a multi worded description
1700 desc
= strtok(NULL
, "\n");
1702 if (strcmp(name
, be_orig_name
) == 0) {
1704 * The first token of the title is
1705 * the old BE name, replace it with
1706 * the new one, and write it out
1707 * along with the remainder of
1708 * description if there is one.
1711 (void) snprintf(new_line
,
1716 (void) snprintf(new_line
,
1718 "title %s\n", be_new_name
);
1721 (void) fputs(new_line
, new_fp
);
1723 (void) fputs(line
, new_fp
);
1726 } else if (strcmp(c
, "bootfs") == 0) {
1728 * Found a 'bootfs' line, parse out the BE root
1731 char *root_ds
= strtok(NULL
, BE_WHITE_SPACE
);
1733 if (root_ds
== NULL
) {
1735 * Nothing after 'bootfs', just push
1738 (void) fputs(line
, new_fp
);
1741 * If this bootfs is the one we're renaming,
1742 * write out the new root dataset value
1744 if (strcmp(root_ds
, be_root_ds
) == 0) {
1745 (void) snprintf(new_line
,
1746 sizeof (new_line
), "bootfs %s\n",
1749 (void) fputs(new_line
, new_fp
);
1751 (void) fputs(line
, new_fp
);
1756 * Found some other line we don't care
1757 * about, write it out.
1759 (void) fputs(line
, new_fp
);
1763 (void) fclose(menu_fp
);
1764 (void) fclose(new_fp
);
1765 (void) close(tmp_fd
);
1767 if (rename(temp_menu
, menu_file
) != 0) {
1769 be_print_err(gettext("be_update_menu: "
1770 "failed to rename file %s to %s: %s\n"),
1771 temp_menu
, menu_file
, strerror(err
));
1772 ret
= errno_to_be_err(err
);
1776 /* Set the perms and ownership of the updated file */
1777 if (chmod(menu_file
, sb
.st_mode
) != 0) {
1779 be_print_err(gettext("be_update_menu: "
1780 "failed to chmod %s: %s\n"), menu_file
, strerror(err
));
1781 ret
= errno_to_be_err(err
);
1784 if (chown(menu_file
, sb
.st_uid
, sb
.st_gid
) != 0) {
1786 be_print_err(gettext("be_update_menu: "
1787 "failed to chown %s: %s\n"), menu_file
, strerror(err
));
1788 ret
= errno_to_be_err(err
);
1793 int err
= BE_SUCCESS
;
1794 err
= be_unmount_pool(zhp
, ptmp_mntpnt
, orig_mntpnt
);
1795 if (ret
== BE_SUCCESS
)
1805 * Function: be_has_menu_entry
1806 * Description: Checks to see if the BEs root dataset has an entry in the grub
1809 * be_dataset - The root dataset of the BE
1810 * be_root_pool - The pool which contains the boot menu
1811 * entry - A pointer the the entry number of the BE if found.
1816 * Semi-private (library wide use only)
1819 be_has_menu_entry(char *be_dataset
, char *be_root_pool
, int *entry
)
1821 zfs_handle_t
*zhp
= NULL
;
1822 char menu_file
[MAXPATHLEN
];
1826 char *rpool_mntpnt
= NULL
;
1827 char *ptmp_mntpnt
= NULL
;
1828 char *orig_mntpnt
= NULL
;
1831 boolean_t pool_mounted
= B_FALSE
;
1835 * Check to see if this system supports grub
1837 if ((zhp
= zfs_open(g_zfs
, be_root_pool
, ZFS_TYPE_DATASET
)) == NULL
) {
1838 be_print_err(gettext("be_has_menu_entry: failed to open "
1839 "pool dataset for %s: %s\n"), be_root_pool
,
1840 libzfs_error_description(g_zfs
));
1845 * Check to see if the pool's dataset is mounted. If it isn't we'll
1846 * attempt to mount it.
1848 if (be_mount_pool(zhp
, &ptmp_mntpnt
, &orig_mntpnt
,
1849 &pool_mounted
) != 0) {
1850 be_print_err(gettext("be_has_menu_entry: pool dataset "
1851 "(%s) could not be mounted\n"), be_root_pool
);
1857 * Get the mountpoint for the root pool dataset.
1859 if (!zfs_is_mounted(zhp
, &rpool_mntpnt
)) {
1860 be_print_err(gettext("be_has_menu_entry: pool "
1861 "dataset (%s) is not mounted. Can't set "
1862 "the default BE in the grub menu.\n"), be_root_pool
);
1867 if (be_has_grub()) {
1868 (void) snprintf(menu_file
, MAXPATHLEN
, "/%s%s",
1869 rpool_mntpnt
, BE_GRUB_MENU
);
1871 (void) snprintf(menu_file
, MAXPATHLEN
, "/%s%s",
1872 rpool_mntpnt
, BE_SPARC_MENU
);
1875 if (be_open_menu(be_root_pool
, menu_file
, &menu_fp
, "r",
1879 } else if (menu_fp
== NULL
) {
1885 rpool_mntpnt
= NULL
;
1887 while (fgets(line
, BUFSIZ
, menu_fp
)) {
1888 char *tok
= strtok_r(line
, BE_WHITE_SPACE
, &last
);
1890 if (tok
!= NULL
&& tok
[0] != '#') {
1891 if (strcmp(tok
, "bootfs") == 0) {
1892 tok
= strtok_r(last
, BE_WHITE_SPACE
, &last
);
1893 if (tok
!= NULL
&& strcmp(tok
,
1895 (void) fclose(menu_fp
);
1897 * The entry number needs to be
1898 * decremented here because the title
1899 * will always be the first line for
1900 * an entry. Because of this we'll
1901 * always be off by one entry when we
1904 *entry
= ent_num
- 1;
1908 } else if (strcmp(tok
, "title") == 0)
1915 (void) be_unmount_pool(zhp
, ptmp_mntpnt
, orig_mntpnt
);
1920 (void) fclose(menu_fp
);
1925 * Function: be_update_vfstab
1926 * Description: This function digs into a BE's vfstab and updates all
1927 * entries with file systems listed in be_fs_list_data_t.
1928 * The entry's root container dataset and be_name will be
1929 * updated with the parameters passed in.
1931 * be_name - name of BE to update
1932 * old_rc_loc - dataset under which the root container dataset
1933 * of the old BE resides in.
1934 * new_rc_loc - dataset under which the root container dataset
1935 * of the new BE resides in.
1936 * fld - be_fs_list_data_t pointer providing the list of
1937 * file systems to look for in vfstab.
1938 * mountpoint - directory of where BE is currently mounted.
1939 * If NULL, then BE is not currently mounted.
1941 * BE_SUCCESS - Success
1942 * be_errno_t - Failure
1944 * Semi-private (library wide use only)
1947 be_update_vfstab(char *be_name
, char *old_rc_loc
, char *new_rc_loc
,
1948 be_fs_list_data_t
*fld
, char *mountpoint
)
1950 char *tmp_mountpoint
= NULL
;
1951 char alt_vfstab
[MAXPATHLEN
];
1952 int ret
= BE_SUCCESS
, err
= BE_SUCCESS
;
1954 if (fld
== NULL
|| fld
->fs_list
== NULL
|| fld
->fs_num
== 0)
1955 return (BE_SUCCESS
);
1957 /* If BE not already mounted, mount the BE */
1958 if (mountpoint
== NULL
) {
1959 if ((ret
= _be_mount(be_name
, &tmp_mountpoint
,
1960 BE_MOUNT_FLAG_NO_ZONES
)) != BE_SUCCESS
) {
1961 be_print_err(gettext("be_update_vfstab: "
1962 "failed to mount BE (%s)\n"), be_name
);
1966 tmp_mountpoint
= mountpoint
;
1969 /* Get string for vfstab in the mounted BE. */
1970 (void) snprintf(alt_vfstab
, sizeof (alt_vfstab
), "%s/etc/vfstab",
1973 /* Update the vfstab */
1974 ret
= _update_vfstab(alt_vfstab
, be_name
, old_rc_loc
, new_rc_loc
,
1977 /* Unmount BE if we mounted it */
1978 if (mountpoint
== NULL
) {
1979 if ((err
= _be_unmount(be_name
, 0)) == BE_SUCCESS
) {
1980 /* Remove temporary mountpoint */
1981 (void) rmdir(tmp_mountpoint
);
1983 be_print_err(gettext("be_update_vfstab: "
1984 "failed to unmount BE %s mounted at %s\n"),
1985 be_name
, tmp_mountpoint
);
1986 if (ret
== BE_SUCCESS
)
1990 free(tmp_mountpoint
);
1997 * Function: be_update_zone_vfstab
1998 * Description: This function digs into a zone BE's vfstab and updates all
1999 * entries with file systems listed in be_fs_list_data_t.
2000 * The entry's root container dataset and be_name will be
2001 * updated with the parameters passed in.
2003 * zhp - zfs_handle_t pointer to zone root dataset.
2004 * be_name - name of zone BE to update
2005 * old_rc_loc - dataset under which the root container dataset
2006 * of the old zone BE resides in.
2007 * new_rc_loc - dataset under which the root container dataset
2008 * of the new zone BE resides in.
2009 * fld - be_fs_list_data_t pointer providing the list of
2010 * file systems to look for in vfstab.
2012 * BE_SUCCESS - Success
2013 * be_errno_t - Failure
2015 * Semi-private (library wide use only)
2018 be_update_zone_vfstab(zfs_handle_t
*zhp
, char *be_name
, char *old_rc_loc
,
2019 char *new_rc_loc
, be_fs_list_data_t
*fld
)
2021 be_mount_data_t md
= { 0 };
2022 be_unmount_data_t ud
= { 0 };
2023 char alt_vfstab
[MAXPATHLEN
];
2024 boolean_t mounted_here
= B_FALSE
;
2025 int ret
= BE_SUCCESS
;
2028 * If zone root not already mounted, mount it at a
2029 * temporary location.
2031 if (!zfs_is_mounted(zhp
, &md
.altroot
)) {
2032 /* Generate temporary mountpoint to mount zone root */
2033 if ((ret
= be_make_tmp_mountpoint(&md
.altroot
)) != BE_SUCCESS
) {
2034 be_print_err(gettext("be_update_zone_vfstab: "
2035 "failed to make temporary mountpoint to "
2036 "mount zone root\n"));
2040 if (be_mount_zone_root(zhp
, &md
) != BE_SUCCESS
) {
2041 be_print_err(gettext("be_update_zone_vfstab: "
2042 "failed to mount zone root %s\n"),
2045 return (BE_ERR_MOUNT_ZONEROOT
);
2047 mounted_here
= B_TRUE
;
2050 /* Get string from vfstab in the mounted zone BE */
2051 (void) snprintf(alt_vfstab
, sizeof (alt_vfstab
), "%s/etc/vfstab",
2054 /* Update the vfstab */
2055 ret
= _update_vfstab(alt_vfstab
, be_name
, old_rc_loc
, new_rc_loc
,
2058 /* Unmount zone root if we mounted it */
2062 if (be_unmount_zone_root(zhp
, &ud
) == BE_SUCCESS
) {
2063 /* Remove the temporary mountpoint */
2064 (void) rmdir(md
.altroot
);
2066 be_print_err(gettext("be_update_zone_vfstab: "
2067 "failed to unmount zone root %s from %s\n"),
2068 zfs_get_name(zhp
), md
.altroot
);
2070 ret
= BE_ERR_UMOUNT_ZONEROOT
;
2079 * Function: be_auto_snap_name
2080 * Description: Generate an auto snapshot name constructed based on the
2081 * current date and time. The auto snapshot name is of the form:
2085 * where <date> is in ISO standard format, so the resultant name
2093 * Success - pointer to auto generated snapshot name. The name
2094 * is allocated in heap storage so the caller is
2095 * responsible for free'ing the name.
2098 * Semi-private (library wide use only)
2101 be_auto_snap_name(void)
2103 time_t utc_tm
= NULL
;
2104 struct tm
*gmt_tm
= NULL
;
2105 char gmt_time_str
[64];
2106 char *auto_snap_name
= NULL
;
2108 if (time(&utc_tm
) == -1) {
2109 be_print_err(gettext("be_auto_snap_name: time() failed\n"));
2113 if ((gmt_tm
= gmtime(&utc_tm
)) == NULL
) {
2114 be_print_err(gettext("be_auto_snap_name: gmtime() failed\n"));
2118 (void) strftime(gmt_time_str
, sizeof (gmt_time_str
), "%F-%T", gmt_tm
);
2120 if ((auto_snap_name
= strdup(gmt_time_str
)) == NULL
) {
2121 be_print_err(gettext("be_auto_snap_name: "
2122 "memory allocation failed\n"));
2126 return (auto_snap_name
);
2130 * Function: be_auto_be_name
2131 * Description: Generate an auto BE name constructed based on the BE name
2132 * of the original BE being cloned.
2134 * obe_name - name of the original BE being cloned.
2136 * Success - pointer to auto generated BE name. The name
2137 * is allocated in heap storage so the caller is
2138 * responsible for free'ing the name.
2141 * Semi-private (library wide use only)
2144 be_auto_be_name(char *obe_name
)
2146 return (be_get_auto_name(obe_name
, NULL
, B_FALSE
));
2150 * Function: be_auto_zone_be_name
2151 * Description: Generate an auto BE name for a zone constructed based on
2152 * the BE name of the original zone BE being cloned.
2154 * container_ds - container dataset for the zone.
2155 * zbe_name - name of the original zone BE being cloned.
2157 * Success - pointer to auto generated BE name. The name
2158 * is allocated in heap storage so the caller is
2159 * responsible for free'ing the name.
2162 * Semi-private (library wide use only)
2165 be_auto_zone_be_name(char *container_ds
, char *zbe_name
)
2167 return (be_get_auto_name(zbe_name
, container_ds
, B_TRUE
));
2171 * Function: be_valid_be_name
2172 * Description: Validates a BE name.
2174 * be_name - name of BE to validate
2176 * B_TRUE - be_name is valid
2177 * B_FALSE - be_name is invalid
2179 * Semi-private (library wide use only)
2183 be_valid_be_name(const char *be_name
)
2185 const char *c
= NULL
;
2186 struct be_defaults be_defaults
;
2188 if (be_name
== NULL
)
2191 be_get_defaults(&be_defaults
);
2194 * A BE name must not be a multi-level dataset name. We also check
2195 * that it does not contain the ' ' and '%' characters. The ' ' is
2196 * a valid character for datasets, however we don't allow that in a
2197 * BE name. The '%' is invalid, but zfs_name_valid() allows it for
2198 * internal reasons, so we explicitly check for it here.
2201 while (*c
!= '\0' && *c
!= '/' && *c
!= ' ' && *c
!= '%')
2208 * The BE name must comply with a zfs dataset filesystem. We also
2209 * verify its length to be < BE_NAME_MAX_LEN.
2211 if (!zfs_name_valid(be_name
, ZFS_TYPE_FILESYSTEM
) ||
2212 strlen(be_name
) > BE_NAME_MAX_LEN
)
2215 if (be_defaults
.be_deflt_bename_starts_with
[0] != '\0' &&
2216 strstr(be_name
, be_defaults
.be_deflt_bename_starts_with
) == NULL
) {
2224 * Function: be_valid_auto_snap_name
2225 * Description: This function checks that a snapshot name is a valid auto
2226 * generated snapshot name. A valid auto generated snapshot
2227 * name is of the form:
2231 * An older form of the auto generated snapshot name also
2232 * included the snapshot's BE cleanup policy and a reserved
2233 * field. Those names will also be verified by this function.
2235 * Examples of valid auto snapshot names are:
2237 * 2008-03-31-18:41:30
2238 * 2008-03-31-22:17:24
2239 * <policy>:-:2008:04-05-09:12:55
2240 * <policy>:-:2008:04-06-15:34:12
2243 * name - name of the snapshot to be validated.
2245 * B_TRUE - the name is a valid auto snapshot name.
2246 * B_FALSE - the name is not a valid auto snapshot name.
2248 * Semi-private (library wide use only)
2251 be_valid_auto_snap_name(char *name
)
2255 char *policy
= NULL
;
2256 char *reserved
= NULL
;
2260 /* Validate the snapshot name by converting it into utc time */
2261 if (strptime(name
, "%Y-%m-%d-%T", &gmt_tm
) != NULL
&&
2262 (mktime(&gmt_tm
) != -1)) {
2267 * Validate the snapshot name against the older form of an
2268 * auto generated snapshot name.
2270 policy
= strdup(name
);
2273 * Get the first field from the snapshot name,
2274 * which is the BE policy
2276 c
= strchr(policy
, ':');
2283 /* Validate the policy name */
2284 if (!valid_be_policy(policy
)) {
2289 /* Get the next field, which is the reserved field. */
2290 if (c
[1] == NULL
|| c
[1] == '\0') {
2295 c
= strchr(reserved
, ':');
2302 /* Validate the reserved field */
2303 if (strcmp(reserved
, "-") != 0) {
2308 /* The remaining string should be the date field */
2309 if (c
[1] == NULL
|| c
[1] == '\0') {
2315 /* Validate the date string by converting it into utc time */
2316 if (strptime(date
, "%Y-%m-%d-%T", &gmt_tm
) == NULL
||
2317 (mktime(&gmt_tm
) == -1)) {
2318 be_print_err(gettext("be_valid_auto_snap_name: "
2319 "invalid auto snapshot name\n"));
2329 * Function: be_default_policy
2330 * Description: Temporary hardcoded policy support. This function returns
2331 * the default policy type to be used to create a BE or a BE
2336 * Name of default BE policy.
2338 * Semi-private (library wide use only)
2341 be_default_policy(void)
2343 return (BE_PLCY_STATIC
);
2347 * Function: valid_be_policy
2348 * Description: Temporary hardcoded policy support. This function valids
2349 * whether a policy is a valid known policy or not.
2351 * policy - name of policy to validate.
2353 * B_TRUE - policy is a valid.
2354 * B_FALSE - policy is invalid.
2356 * Semi-private (library wide use only)
2359 valid_be_policy(char *policy
)
2364 if (strcmp(policy
, BE_PLCY_STATIC
) == 0 ||
2365 strcmp(policy
, BE_PLCY_VOLATILE
) == 0) {
2373 * Function: be_print_err
2374 * Description: This function prints out error messages if do_print is
2375 * set to B_TRUE or if the BE_PRINT_ERR environment variable
2378 * prnt_str - the string we wish to print and any arguments
2379 * for the format of that string.
2383 * Semi-private (library wide use only)
2386 be_print_err(char *prnt_str
, ...)
2391 static boolean_t env_checked
= B_FALSE
;
2394 if ((env_buf
= getenv("BE_PRINT_ERR")) != NULL
) {
2395 if (strcasecmp(env_buf
, "true") == 0) {
2399 env_checked
= B_TRUE
;
2403 va_start(ap
, prnt_str
);
2404 /* LINTED variable format specifier */
2405 (void) vsnprintf(buf
, BUFSIZ
, prnt_str
, ap
);
2406 (void) fputs(buf
, stderr
);
2412 * Function: be_find_current_be
2413 * Description: Find the currently "active" BE. Fill in the
2414 * passed in be_transaction_data_t reference with the
2419 * BE_SUCCESS - Success
2420 * be_errnot_t - Failure
2422 * Semi-private (library wide use only)
2424 * The caller is responsible for initializing the libzfs handle
2425 * and freeing the memory used by the active be_name.
2428 be_find_current_be(be_transaction_data_t
*bt
)
2432 if ((zret
= zpool_iter(g_zfs
, be_zpool_find_current_be_callback
,
2434 be_print_err(gettext("be_find_current_be: failed to "
2435 "find current BE name\n"));
2436 return (BE_ERR_BE_NOENT
);
2437 } else if (zret
< 0) {
2438 be_print_err(gettext("be_find_current_be: "
2439 "zpool_iter failed: %s\n"),
2440 libzfs_error_description(g_zfs
));
2441 return (zfs_err_to_be_err(g_zfs
));
2444 return (BE_SUCCESS
);
2448 * Function: be_zpool_find_current_be_callback
2449 * Description: Callback function used to iterate through all existing pools
2450 * to find the BE that is the currently booted BE.
2452 * zlp - zpool_handle_t pointer to the current pool being
2454 * data - be_transaction_data_t pointer.
2455 * Upon successfully finding the current BE, the
2456 * obe_zpool member of this parameter is set to the
2457 * pool it is found in.
2459 * 1 - Found current BE in this pool.
2460 * 0 - Did not find current BE in this pool.
2462 * Semi-private (library wide use only)
2465 be_zpool_find_current_be_callback(zpool_handle_t
*zlp
, void *data
)
2467 be_transaction_data_t
*bt
= data
;
2468 zfs_handle_t
*zhp
= NULL
;
2469 const char *zpool
= zpool_get_name(zlp
);
2470 char be_container_ds
[MAXPATHLEN
];
2474 * Generate string for BE container dataset
2476 if (getzoneid() != GLOBAL_ZONEID
) {
2477 if ((zpath
= be_get_ds_from_dir("/")) != NULL
) {
2478 (void) strlcpy(be_container_ds
, dirname(zpath
),
2479 sizeof (be_container_ds
));
2481 be_print_err(gettext(
2482 "be_zpool_find_current_be_callback: "
2483 "zone root dataset is not mounted\n"));
2487 be_make_container_ds(zpool
, be_container_ds
,
2488 sizeof (be_container_ds
));
2492 * Check if a BE container dataset exists in this pool.
2494 if (!zfs_dataset_exists(g_zfs
, be_container_ds
, ZFS_TYPE_FILESYSTEM
)) {
2500 * Get handle to this zpool's BE container dataset.
2502 if ((zhp
= zfs_open(g_zfs
, be_container_ds
, ZFS_TYPE_FILESYSTEM
)) ==
2504 be_print_err(gettext("be_zpool_find_current_be_callback: "
2505 "failed to open BE container dataset (%s)\n"),
2512 * Iterate through all potential BEs in this zpool
2514 if (zfs_iter_filesystems(zhp
, be_zfs_find_current_be_callback
, bt
)) {
2516 * Found current BE dataset; set obe_zpool
2518 if ((bt
->obe_zpool
= strdup(zpool
)) == NULL
) {
2519 be_print_err(gettext(
2520 "be_zpool_find_current_be_callback: "
2521 "memory allocation failed\n"));
2539 * Function: be_zfs_find_current_be_callback
2540 * Description: Callback function used to iterate through all BEs in a
2541 * pool to find the BE that is the currently booted BE.
2543 * zhp - zfs_handle_t pointer to current filesystem being checked.
2544 * data - be_transaction-data_t pointer
2545 * Upon successfully finding the current BE, the
2546 * obe_name and obe_root_ds members of this parameter
2547 * are set to the BE name and BE's root dataset
2550 * 1 - Found current BE.
2551 * 0 - Did not find current BE.
2553 * Semi-private (library wide use only)
2556 be_zfs_find_current_be_callback(zfs_handle_t
*zhp
, void *data
)
2558 be_transaction_data_t
*bt
= data
;
2562 * Check if dataset is mounted, and if so where.
2564 if (zfs_is_mounted(zhp
, &mp
)) {
2566 * If mounted at root, set obe_root_ds and obe_name
2568 if (mp
!= NULL
&& strcmp(mp
, "/") == 0) {
2571 if ((bt
->obe_root_ds
= strdup(zfs_get_name(zhp
)))
2573 be_print_err(gettext(
2574 "be_zfs_find_current_be_callback: "
2575 "memory allocation failed\n"));
2580 if ((bt
->obe_name
= strdup(basename(bt
->obe_root_ds
)))
2582 be_print_err(gettext(
2583 "be_zfs_find_current_be_callback: "
2584 "memory allocation failed\n"));
2601 * Function: be_check_be_roots_callback
2602 * Description: This function checks whether or not the dataset name passed
2603 * is hierachically located under the BE root container dataset
2606 * zlp - zpool_handle_t pointer to current pool being processed.
2607 * data - name of dataset to check
2609 * 0 - dataset is not in this pool's BE root container dataset
2610 * 1 - dataset is in this pool's BE root container dataset
2612 * Semi-private (library wide use only)
2615 be_check_be_roots_callback(zpool_handle_t
*zlp
, void *data
)
2617 const char *zpool
= zpool_get_name(zlp
);
2619 char be_container_ds
[MAXPATHLEN
];
2621 /* Generate string for this pool's BE root container dataset */
2622 be_make_container_ds(zpool
, be_container_ds
, sizeof (be_container_ds
));
2625 * If dataset lives under the BE root container dataset
2626 * of this pool, return failure.
2628 if (strncmp(be_container_ds
, ds
, strlen(be_container_ds
)) == 0 &&
2629 ds
[strlen(be_container_ds
)] == '/') {
2639 * Function: zfs_err_to_be_err
2640 * Description: This function takes the error stored in the libzfs handle
2641 * and maps it to an be_errno_t. If there are no matching
2642 * be_errno_t's then BE_ERR_ZFS is returned.
2644 * zfsh - The libzfs handle containing the error we're looking up.
2648 * Semi-private (library wide use only)
2651 zfs_err_to_be_err(libzfs_handle_t
*zfsh
)
2653 int err
= libzfs_errno(zfsh
);
2657 return (BE_SUCCESS
);
2659 return (BE_ERR_PERM
);
2661 return (BE_ERR_INTR
);
2663 return (BE_ERR_NOENT
);
2665 return (BE_ERR_NOSPC
);
2666 case EZFS_MOUNTFAILED
:
2667 return (BE_ERR_MOUNT
);
2668 case EZFS_UMOUNTFAILED
:
2669 return (BE_ERR_UMOUNT
);
2671 return (BE_ERR_BE_EXISTS
);
2673 return (BE_ERR_DEV_BUSY
);
2674 case EZFS_POOLREADONLY
:
2675 return (BE_ERR_ROFS
);
2676 case EZFS_NAMETOOLONG
:
2677 return (BE_ERR_NAMETOOLONG
);
2679 return (BE_ERR_NODEV
);
2680 case EZFS_POOL_INVALARG
:
2681 return (BE_ERR_INVAL
);
2683 return (BE_ERR_INVALPROP
);
2685 return (BE_ERR_DSTYPE
);
2686 case EZFS_PROPNONINHERIT
:
2687 return (BE_ERR_NONINHERIT
);
2688 case EZFS_PROPREADONLY
:
2689 return (BE_ERR_READONLYPROP
);
2690 case EZFS_RESILVERING
:
2691 case EZFS_POOLUNAVAIL
:
2692 return (BE_ERR_UNAVAIL
);
2693 case EZFS_DSREADONLY
:
2694 return (BE_ERR_READONLYDS
);
2696 return (BE_ERR_ZFS
);
2701 * Function: errno_to_be_err
2702 * Description: This function takes an errno and maps it to an be_errno_t.
2703 * If there are no matching be_errno_t's then BE_ERR_UNKNOWN is
2706 * err - The errno we're compairing against.
2710 * Semi-private (library wide use only)
2713 errno_to_be_err(int err
)
2717 return (BE_ERR_PERM
);
2719 return (BE_ERR_ACCESS
);
2721 return (BE_ERR_CANCELED
);
2723 return (BE_ERR_INTR
);
2725 return (BE_ERR_NOENT
);
2728 return (BE_ERR_NOSPC
);
2730 return (BE_ERR_BE_EXISTS
);
2732 return (BE_ERR_BUSY
);
2734 return (BE_ERR_ROFS
);
2736 return (BE_ERR_NAMETOOLONG
);
2738 return (BE_ERR_NXIO
);
2740 return (BE_ERR_INVAL
);
2742 return (BE_ERR_FAULT
);
2744 return (BE_ERR_UNKNOWN
);
2749 * Function: be_err_to_str
2750 * Description: This function takes a be_errno_t and maps it to a message.
2751 * If there are no matching be_errno_t's then NULL is returned.
2753 * be_errno_t - The be_errno_t we're mapping.
2755 * string or NULL if the error code is not known.
2757 * Semi-private (library wide use only)
2760 be_err_to_str(int err
)
2764 return (gettext("Permission denied."));
2765 case BE_ERR_ACTIVATE_CURR
:
2766 return (gettext("Activation of current BE failed."));
2767 case BE_ERR_AUTONAME
:
2768 return (gettext("Auto naming failed."));
2769 case BE_ERR_BE_NOENT
:
2770 return (gettext("No such BE."));
2772 return (gettext("Mount busy."));
2773 case BE_ERR_DEV_BUSY
:
2774 return (gettext("Device busy."));
2775 case BE_ERR_CANCELED
:
2776 return (gettext("Operation canceled."));
2778 return (gettext("BE clone failed."));
2780 return (gettext("BE copy failed."));
2781 case BE_ERR_CREATDS
:
2782 return (gettext("Dataset creation failed."));
2783 case BE_ERR_CURR_BE_NOT_FOUND
:
2784 return (gettext("Can't find current BE."));
2785 case BE_ERR_DESTROY
:
2786 return (gettext("Failed to destroy BE or snapshot."));
2787 case BE_ERR_DESTROY_CURR_BE
:
2788 return (gettext("Cannot destroy current BE."));
2790 return (gettext("BE demotion failed."));
2792 return (gettext("Invalid dataset type."));
2793 case BE_ERR_BE_EXISTS
:
2794 return (gettext("BE exists."));
2796 return (gettext("be_zfs_init failed."));
2798 return (gettext("Interupted system call."));
2800 return (gettext("Invalid argument."));
2801 case BE_ERR_INVALPROP
:
2802 return (gettext("Invalid property for dataset."));
2803 case BE_ERR_INVALMOUNTPOINT
:
2804 return (gettext("Unexpected mountpoint."));
2806 return (gettext("Mount failed."));
2807 case BE_ERR_MOUNTED
:
2808 return (gettext("Already mounted."));
2809 case BE_ERR_NAMETOOLONG
:
2810 return (gettext("name > BUFSIZ."));
2812 return (gettext("Doesn't exist."));
2813 case BE_ERR_POOL_NOENT
:
2814 return (gettext("No such pool."));
2816 return (gettext("No such device."));
2817 case BE_ERR_NOTMOUNTED
:
2818 return (gettext("File system not mounted."));
2820 return (gettext("Not enough memory."));
2821 case BE_ERR_NONINHERIT
:
2823 "Property is not inheritable for the BE dataset."));
2825 return (gettext("No such device or address."));
2827 return (gettext("No space on device."));
2829 return (gettext("Operation not supported."));
2831 return (gettext("Open failed."));
2833 return (gettext("Not owner."));
2834 case BE_ERR_UNAVAIL
:
2835 return (gettext("The BE is currently unavailable."));
2836 case BE_ERR_PROMOTE
:
2837 return (gettext("BE promotion failed."));
2839 return (gettext("Read only file system."));
2840 case BE_ERR_READONLYDS
:
2841 return (gettext("Read only dataset."));
2842 case BE_ERR_READONLYPROP
:
2843 return (gettext("Read only property."));
2844 case BE_ERR_RENAME_ACTIVE
:
2845 return (gettext("Renaming the active BE is not supported."));
2846 case BE_ERR_SS_EXISTS
:
2847 return (gettext("Snapshot exists."));
2848 case BE_ERR_SS_NOENT
:
2849 return (gettext("No such snapshot."));
2851 return (gettext("Unmount failed."));
2852 case BE_ERR_UMOUNT_CURR_BE
:
2853 return (gettext("Can't unmount the current BE."));
2854 case BE_ERR_UMOUNT_SHARED
:
2855 return (gettext("Unmount of a shared File System failed."));
2857 return (gettext("Bad address."));
2858 case BE_ERR_UNKNOWN
:
2859 return (gettext("Unknown error."));
2861 return (gettext("ZFS returned an error."));
2862 case BE_ERR_GEN_UUID
:
2863 return (gettext("Failed to generate uuid."));
2864 case BE_ERR_PARSE_UUID
:
2865 return (gettext("Failed to parse uuid."));
2866 case BE_ERR_NO_UUID
:
2867 return (gettext("No uuid"));
2868 case BE_ERR_ZONE_NO_PARENTBE
:
2869 return (gettext("No parent uuid"));
2870 case BE_ERR_ZONE_MULTIPLE_ACTIVE
:
2871 return (gettext("Multiple active zone roots"));
2872 case BE_ERR_ZONE_NO_ACTIVE_ROOT
:
2873 return (gettext("No active zone root"));
2874 case BE_ERR_ZONE_ROOT_NOT_LEGACY
:
2875 return (gettext("Zone root not legacy"));
2876 case BE_ERR_MOUNT_ZONEROOT
:
2877 return (gettext("Failed to mount a zone root."));
2878 case BE_ERR_UMOUNT_ZONEROOT
:
2879 return (gettext("Failed to unmount a zone root."));
2880 case BE_ERR_NO_MOUNTED_ZONE
:
2881 return (gettext("Zone is not mounted"));
2882 case BE_ERR_ZONES_UNMOUNT
:
2883 return (gettext("Unable to unmount a zone BE."));
2884 case BE_ERR_NO_MENU
:
2885 return (gettext("Missing boot menu file."));
2886 case BE_ERR_BAD_MENU_PATH
:
2887 return (gettext("Invalid path for menu.lst file"));
2888 case BE_ERR_ZONE_SS_EXISTS
:
2889 return (gettext("Zone snapshot exists."));
2890 case BE_ERR_BOOTFILE_INST
:
2891 return (gettext("Error installing boot files."));
2893 return (gettext("Error running an external command."));
2900 * Function: be_has_grub
2901 * Description: Boolean function indicating whether the current system
2903 * Return: B_FALSE - the system does not have grub
2904 * B_TRUE - the system does have grub.
2906 * Semi-private (library wide use only)
2912 * TODO: This will need to be expanded to check for the existence of
2913 * grub if and when there is grub support for SPARC.
2915 return (be_is_isa("i386"));
2919 * Function: be_is_isa
2920 * Description: Boolean function indicating whether the instruction set
2921 * architecture of the executing system matches the name provided.
2922 * The string must match a system defined architecture (e.g.
2923 * "i386", "sparc") and is case sensitive.
2924 * Parameters: name - string representing the name of instruction set
2925 * architecture being tested
2926 * Returns: B_FALSE - the system instruction set architecture is different
2927 * from the one specified
2928 * B_TRUE - the system instruction set architecture is the same
2929 * as the one specified
2931 * Semi-private (library wide use only)
2934 be_is_isa(char *name
)
2936 return ((strcmp((char *)be_get_default_isa(), name
) == 0));
2940 * Function: be_get_default_isa
2942 * Returns the default instruction set architecture of the
2943 * machine it is executed on. (eg. sparc, i386, ...)
2944 * NOTE: SYS_INST environment variable may override default
2949 * NULL - the architecture returned by sysinfo() was too
2950 * long for local variables
2951 * char * - pointer to a string containing the default
2954 * Semi-private (library wide use only)
2957 be_get_default_isa(void)
2961 static char default_inst
[ARCH_LENGTH
] = "";
2963 if (default_inst
[0] == '\0') {
2964 if ((envp
= getenv("SYS_INST")) != NULL
) {
2965 if ((int)strlen(envp
) >= ARCH_LENGTH
)
2968 (void) strcpy(default_inst
, envp
);
2970 i
= sysinfo(SI_ARCHITECTURE
, default_inst
, ARCH_LENGTH
);
2971 if (i
< 0 || i
> ARCH_LENGTH
)
2975 return (default_inst
);
2979 * Function: be_run_cmd
2981 * Runs a command in a separate subprocess. Splits out stdout from stderr
2982 * and sends each to its own buffer. Buffers must be pre-allocated and
2983 * passed in as arguments. Buffer sizes are also passed in as arguments.
2986 * - Command being run is assumed to not have any stdout or stderr
2988 * - Commands which emit total stderr output of greater than PIPE_BUF
2989 * bytes can hang. For such commands, a different implementation
2990 * which uses poll(2) must be used.
2991 * - stdout_buf can be NULL. In this case, stdout_bufsize is ignored, and
2992 * the stream which would have gone to it is sent to the bit
2994 * - stderr_buf cannot be NULL.
2995 * - Only subprocess errors are appended to the stderr_buf. Errors
2996 * running the command are reported through be_print_err().
2997 * - Data which would overflow its respective buffer is sent to the bit
3001 * command: command to run. Assumed not to have embedded stdout
3002 * or stderr redirection. May have stdin redirection,
3004 * stderr_buf: buffer returning subprocess stderr data. Errors
3005 * reported by this function are reported through
3007 * stderr_bufsize: size of stderr_buf
3008 * stdout_buf: buffer returning subprocess stdout data.
3009 * stdout_bufsize: size of stdout_buf
3011 * BE_SUCCESS - The command ran successfully without returning
3014 * - The command could not be run.
3015 * - The command terminated with error status.
3016 * - There were errors extracting or returning subprocess
3018 * BE_ERR_NOMEM - The command exceeds the command buffer size.
3019 * BE_ERR_INVAL - An invalid argument was specified.
3021 * Semi-private (library wide use only)
3024 be_run_cmd(char *command
, char *stderr_buf
, int stderr_bufsize
,
3025 char *stdout_buf
, int stdout_bufsize
)
3027 char *temp_filename
= strdup(tmpnam(NULL
));
3028 FILE *stdout_str
= NULL
;
3029 FILE *stderr_str
= NULL
;
3030 char cmdline
[BUFSIZ
];
3031 char oneline
[BUFSIZ
];
3033 int rval
= BE_SUCCESS
;
3035 if ((command
== NULL
) || (stderr_buf
== NULL
) ||
3036 (stderr_bufsize
<= 0) || (stdout_bufsize
< 0) ||
3037 ((stdout_buf
!= NULL
) ^ (stdout_bufsize
!= 0))) {
3038 return (BE_ERR_INVAL
);
3041 /* Set up command so popen returns stderr, not stdout */
3042 if (snprintf(cmdline
, BUFSIZ
, "%s 2> %s", command
,
3043 temp_filename
) >= BUFSIZ
) {
3044 rval
= BE_ERR_NOMEM
;
3048 /* Set up the fifo that will make stderr available. */
3049 if (mkfifo(temp_filename
, 0600) != 0) {
3050 (void) be_print_err(gettext("be_run_cmd: mkfifo: %s\n"),
3052 rval
= BE_ERR_EXTCMD
;
3056 if ((stdout_str
= popen(cmdline
, "r")) == NULL
) {
3057 (void) be_print_err(gettext("be_run_cmd: popen: %s\n"),
3059 rval
= BE_ERR_EXTCMD
;
3063 if ((stderr_str
= fopen(temp_filename
, "r")) == NULL
) {
3064 (void) be_print_err(gettext("be_run_cmd: fopen: %s\n"),
3066 (void) pclose(stdout_str
);
3067 rval
= BE_ERR_EXTCMD
;
3071 /* Read stdout first, as it usually outputs more than stderr. */
3072 oneline
[BUFSIZ
-1] = '\0';
3073 while (fgets(oneline
, BUFSIZ
-1, stdout_str
) != NULL
) {
3074 if (stdout_str
!= NULL
) {
3075 (void) strlcat(stdout_buf
, oneline
, stdout_bufsize
);
3079 while (fgets(oneline
, BUFSIZ
-1, stderr_str
) != NULL
) {
3080 (void) strlcat(stderr_buf
, oneline
, stderr_bufsize
);
3083 /* Close pipe, get exit status. */
3084 if ((exit_status
= pclose(stdout_str
)) == -1) {
3085 (void) be_print_err(gettext("be_run_cmd: pclose: %s\n"),
3087 rval
= BE_ERR_EXTCMD
;
3088 } else if (WIFEXITED(exit_status
)) {
3089 exit_status
= (int)((char)WEXITSTATUS(exit_status
));
3090 if (exit_status
!= 0) {
3091 (void) snprintf(oneline
, BUFSIZ
, gettext("be_run_cmd: "
3092 "command terminated with error status: %d\n"),
3094 (void) strlcat(stderr_buf
, oneline
, stderr_bufsize
);
3095 rval
= BE_ERR_EXTCMD
;
3098 (void) snprintf(oneline
, BUFSIZ
, gettext("be_run_cmd: command "
3099 "terminated on signal: %s\n"),
3100 strsignal(WTERMSIG(exit_status
)));
3101 (void) strlcat(stderr_buf
, oneline
, stderr_bufsize
);
3102 rval
= BE_ERR_EXTCMD
;
3106 (void) unlink(temp_filename
);
3107 (void) free(temp_filename
);
3112 /* ******************************************************************** */
3113 /* Private Functions */
3114 /* ******************************************************************** */
3117 * Function: update_dataset
3118 * Description: This function takes a dataset name and replaces the zpool
3119 * and be_name components of the dataset with the new be_name
3122 * dataset - name of dataset
3123 * dataset_len - lenth of buffer in which dataset is passed in.
3124 * be_name - name of new BE name to update to.
3125 * old_rc_loc - dataset under which the root container dataset
3126 * for the old BE lives.
3127 * new_rc_loc - dataset under which the root container dataset
3128 * for the new BE lives.
3130 * BE_SUCCESS - Success
3131 * be_errno_t - Failure
3136 update_dataset(char *dataset
, int dataset_len
, char *be_name
,
3137 char *old_rc_loc
, char *new_rc_loc
)
3140 char *sub_ds
= NULL
;
3142 /* Tear off the BE container dataset */
3143 if ((ds
= be_make_name_from_ds(dataset
, old_rc_loc
)) == NULL
) {
3144 return (BE_ERR_INVAL
);
3147 /* Get dataset name relative to BE root, if there is one */
3148 sub_ds
= strchr(ds
, '/');
3150 /* Generate the BE root dataset name */
3151 be_make_root_ds(new_rc_loc
, be_name
, dataset
, dataset_len
);
3153 /* If a subordinate dataset name was found, append it */
3155 (void) strlcat(dataset
, sub_ds
, dataset_len
);
3158 return (BE_SUCCESS
);
3162 * Function: _update_vfstab
3163 * Description: This function updates a vfstab file to reflect the new
3164 * root container dataset location and be_name for all
3165 * entries listed in the be_fs_list_data_t structure passed in.
3167 * vfstab - vfstab file to modify
3168 * be_name - name of BE to update.
3169 * old_rc_loc - dataset under which the root container dataset
3170 * of the old BE resides in.
3171 * new_rc_loc - dataset under which the root container dataset
3172 * of the new BE resides in.
3173 * fld - be_fs_list_data_t pointer providing the list of
3174 * file systems to look for in vfstab.
3176 * BE_SUCCESS - Success
3177 * be_errno_t - Failure
3182 _update_vfstab(char *vfstab
, char *be_name
, char *old_rc_loc
,
3183 char *new_rc_loc
, be_fs_list_data_t
*fld
)
3186 char *tmp_vfstab
= NULL
;
3187 char comments_buf
[BUFSIZ
];
3188 FILE *comments
= NULL
;
3189 FILE *vfs_ents
= NULL
;
3192 char dev
[MAXPATHLEN
];
3195 int ret
= BE_SUCCESS
, err
= 0;
3197 int tmp_vfstab_len
= 0;
3202 * Open vfstab for reading twice. First is for comments,
3203 * second is for actual entries.
3205 if ((comments
= fopen(vfstab
, "r")) == NULL
||
3206 (vfs_ents
= fopen(vfstab
, "r")) == NULL
) {
3208 be_print_err(gettext("_update_vfstab: "
3209 "failed to open vfstab (%s): %s\n"), vfstab
,
3211 ret
= errno_to_be_err(err
);
3215 /* Grab the stats of the original vfstab file */
3216 if (stat(vfstab
, &sb
) != 0) {
3218 be_print_err(gettext("_update_vfstab: "
3219 "failed to stat file %s: %s\n"), vfstab
,
3221 ret
= errno_to_be_err(err
);
3225 /* Create tmp file for modified vfstab */
3226 if ((tmp_vfstab
= (char *)malloc(strlen(vfstab
) + 7))
3228 be_print_err(gettext("_update_vfstab: "
3229 "malloc failed\n"));
3233 tmp_vfstab_len
= strlen(vfstab
) + 7;
3234 (void) memset(tmp_vfstab
, 0, tmp_vfstab_len
);
3235 (void) strlcpy(tmp_vfstab
, vfstab
, tmp_vfstab_len
);
3236 (void) strlcat(tmp_vfstab
, "XXXXXX", tmp_vfstab_len
);
3237 if ((fd
= mkstemp(tmp_vfstab
)) == -1) {
3239 be_print_err(gettext("_update_vfstab: "
3240 "mkstemp failed: %s\n"), strerror(err
));
3241 ret
= errno_to_be_err(err
);
3244 if ((tfile
= fdopen(fd
, "w")) == NULL
) {
3246 be_print_err(gettext("_update_vfstab: "
3247 "could not open file for write\n"));
3249 ret
= errno_to_be_err(err
);
3253 while (fgets(comments_buf
, BUFSIZ
, comments
)) {
3254 for (c
= comments_buf
; *c
!= '\0' && isspace(*c
); c
++)
3258 } else if (*c
== '#') {
3260 * If line is a comment line, just put
3261 * it through to the tmp vfstab.
3263 (void) fputs(comments_buf
, tfile
);
3266 * Else line is a vfstab entry, grab it
3267 * into a vfstab struct.
3269 if (getvfsent(vfs_ents
, &vp
) != 0) {
3271 be_print_err(gettext("_update_vfstab: "
3272 "getvfsent failed: %s\n"), strerror(err
));
3273 ret
= errno_to_be_err(err
);
3277 if (vp
.vfs_special
== NULL
|| vp
.vfs_mountp
== NULL
) {
3278 (void) putvfsent(tfile
, &vp
);
3283 * If the entry is one of the entries in the list
3284 * of file systems to update, modify it's device
3285 * field to be correct for this BE.
3287 for (i
= 0; i
< fld
->fs_num
; i
++) {
3288 if (strcmp(vp
.vfs_special
, fld
->fs_list
[i
])
3291 * Found entry that needs an update.
3292 * Replace the root container dataset
3293 * location and be_name in the
3296 (void) strlcpy(dev
, vp
.vfs_special
,
3299 if ((ret
= update_dataset(dev
,
3300 sizeof (dev
), be_name
, old_rc_loc
,
3301 new_rc_loc
)) != 0) {
3303 gettext("_update_vfstab: "
3304 "Failed to update device "
3305 "field for vfstab entry "
3306 "%s\n"), fld
->fs_list
[i
]);
3310 vp
.vfs_special
= dev
;
3315 /* Put entry through to tmp vfstab */
3316 (void) putvfsent(tfile
, &vp
);
3320 (void) fclose(comments
);
3322 (void) fclose(vfs_ents
);
3324 (void) fclose(tfile
);
3327 /* Copy tmp vfstab into place */
3328 if (rename(tmp_vfstab
, vfstab
) != 0) {
3330 be_print_err(gettext("_update_vfstab: "
3331 "failed to rename file %s to %s: %s\n"), tmp_vfstab
,
3332 vfstab
, strerror(err
));
3333 ret
= errno_to_be_err(err
);
3337 /* Set the perms and ownership of the updated file */
3338 if (chmod(vfstab
, sb
.st_mode
) != 0) {
3340 be_print_err(gettext("_update_vfstab: "
3341 "failed to chmod %s: %s\n"), vfstab
, strerror(err
));
3342 ret
= errno_to_be_err(err
);
3345 if (chown(vfstab
, sb
.st_uid
, sb
.st_gid
) != 0) {
3347 be_print_err(gettext("_update_vfstab: "
3348 "failed to chown %s: %s\n"), vfstab
, strerror(err
));
3349 ret
= errno_to_be_err(err
);
3354 if (comments
!= NULL
)
3355 (void) fclose(comments
);
3356 if (vfs_ents
!= NULL
)
3357 (void) fclose(vfs_ents
);
3358 (void) unlink(tmp_vfstab
);
3359 (void) free(tmp_vfstab
);
3361 (void) fclose(tfile
);
3368 * Function: be_get_auto_name
3369 * Description: Generate an auto name constructed based on the BE name
3370 * of the original BE or zone BE being cloned.
3372 * obe_name - name of the original BE or zone BE being cloned.
3373 * container_ds - container dataset for the zone.
3374 * Note: if zone_be is false this should be
3376 * zone_be - flag that indicates if we are operating on a zone BE.
3378 * Success - pointer to auto generated BE name. The name
3379 * is allocated in heap storage so the caller is
3380 * responsible for free'ing the name.
3386 be_get_auto_name(char *obe_name
, char *be_container_ds
, boolean_t zone_be
)
3388 be_node_list_t
*be_nodes
= NULL
;
3389 be_node_list_t
*cur_be
= NULL
;
3390 char auto_be_name
[MAXPATHLEN
];
3391 char base_be_name
[MAXPATHLEN
];
3392 char cur_be_name
[MAXPATHLEN
];
3393 char *num_str
= NULL
;
3401 * Check if obe_name is already in an auto BE name format.
3402 * If it is, then strip off the increment number to get the
3405 (void) strlcpy(base_be_name
, obe_name
, sizeof (base_be_name
));
3407 if ((num_str
= strrchr(base_be_name
, BE_AUTO_NAME_DELIM
))
3409 /* Make sure remaining string is all digits */
3411 while (c
[0] != '\0' && isdigit(c
[0]))
3414 * If we're now at the end of the string strip off the
3422 if (be_container_ds
== NULL
)
3424 if (be_get_zone_be_list(obe_name
, be_container_ds
,
3425 &be_nodes
) != BE_SUCCESS
) {
3426 be_print_err(gettext("be_get_auto_name: "
3427 "be_get_zone_be_list failed\n"));
3430 } else if (_be_list(NULL
, &be_nodes
) != BE_SUCCESS
) {
3431 be_print_err(gettext("be_get_auto_name: be_list failed\n"));
3435 for (cur_be
= be_nodes
; cur_be
!= NULL
; cur_be
= cur_be
->be_next_node
) {
3436 (void) strlcpy(cur_be_name
, cur_be
->be_node_name
,
3437 sizeof (cur_be_name
));
3439 /* If cur_be_name doesn't match at least base be name, skip. */
3440 if (strncmp(cur_be_name
, base_be_name
, strlen(base_be_name
))
3444 /* Get the string following the base be name */
3445 num_str
= cur_be_name
+ strlen(base_be_name
);
3448 * If nothing follows the base be name, this cur_be_name
3449 * is the BE named with the base be name, skip.
3451 if (num_str
== NULL
|| num_str
[0] == '\0')
3455 * Remove the name delimiter. If its not there,
3456 * cur_be_name isn't part of this BE name stream, skip.
3458 if (num_str
[0] == BE_AUTO_NAME_DELIM
)
3463 /* Make sure remaining string is all digits */
3465 while (c
[0] != '\0' && isdigit(c
[0]))
3470 /* Convert the number string to an int */
3471 cur_num
= atoi(num_str
);
3474 * If failed to convert the string, skip it. If its too
3475 * long to be converted to an int, we wouldn't auto generate
3476 * this number anyway so there couldn't be a conflict.
3477 * We treat it as a manually created BE name.
3479 if (cur_num
== 0 && errno
== EINVAL
)
3483 * Compare current number to current max number,
3484 * take higher of the two.
3491 * Store off a copy of 'num' incase we need it later. If incrementing
3492 * 'num' causes it to roll over, this means 'num' is the largest
3493 * positive int possible; we'll need it later in the loop to determine
3494 * if we've exhausted all possible increment numbers. We store it in
3499 /* Increment 'num' to get new auto BE name number */
3504 * Since incrementing 'num' caused it to rollover, start
3505 * over at 0 and find the first available number.
3507 for (num
= 0; num
< cur_num
; num
++) {
3509 (void) snprintf(cur_be_name
, sizeof (cur_be_name
),
3510 "%s%c%d", base_be_name
, BE_AUTO_NAME_DELIM
, num
);
3512 ret
= zpool_iter(g_zfs
, be_exists_callback
,
3517 * BE name doesn't exist, break out
3521 } else if (ret
== 1) {
3522 /* BE name exists, continue looking */
3525 be_print_err(gettext("be_get_auto_name: "
3526 "zpool_iter failed: %s\n"),
3527 libzfs_error_description(g_zfs
));
3528 be_free_list(be_nodes
);
3534 * If 'num' equals 'cur_num', we've exhausted all possible
3535 * auto BE names for this base BE name.
3537 if (num
== cur_num
) {
3538 be_print_err(gettext("be_get_auto_name: "
3539 "No more available auto BE names for base "
3540 "BE name %s\n"), base_be_name
);
3541 be_free_list(be_nodes
);
3546 be_free_list(be_nodes
);
3549 * Generate string for auto BE name.
3551 (void) snprintf(auto_be_name
, sizeof (auto_be_name
), "%s%c%d",
3552 base_be_name
, BE_AUTO_NAME_DELIM
, num
);
3554 if ((c
= strdup(auto_be_name
)) == NULL
) {
3555 be_print_err(gettext("be_get_auto_name: "
3556 "memory allocation failed\n"));
3564 * Function: be_get_console_prop
3565 * Description: Determine console device.
3567 * Success - pointer to console setting.
3573 be_get_console_prop(void)
3576 char *console
= NULL
;
3578 if ((dn
= di_init("/", DINFOPROP
)) == DI_NODE_NIL
) {
3579 be_print_err(gettext("be_get_console_prop: "
3580 "di_init() failed\n"));
3584 if (di_prop_lookup_strings(DDI_DEV_T_ANY
, dn
,
3585 "console", &console
) != -1) {
3590 if (console
== NULL
) {
3591 if (di_prop_lookup_strings(DDI_DEV_T_ANY
, dn
,
3592 "output-device", &console
) != -1) {
3594 if (strncmp(console
, "screen", strlen("screen")) == 0)
3595 console
= BE_DEFAULT_CONSOLE
;
3600 * Default console to text
3602 if (console
== NULL
) {
3603 console
= BE_DEFAULT_CONSOLE
;
3610 * Function: be_create_menu
3612 * This function is used if no menu.lst file exists. In
3613 * this case a new file is created and if needed default
3614 * lines are added to the file.
3616 * pool - The name of the pool the menu.lst file is on
3617 * menu_file - The name of the file we're creating.
3618 * menu_fp - A pointer to the file pointer of the file we
3619 * created. This is also used to pass back the file
3620 * pointer to the newly created file.
3621 * mode - the original mode used for the failed attempt to
3622 * non-existent file.
3624 * BE_SUCCESS - Success
3625 * be_errno_t - Failure
3636 be_node_list_t
*be_nodes
= NULL
;
3637 char *menu_path
= NULL
;
3638 char *be_rpool
= NULL
;
3639 char *be_name
= NULL
;
3640 char *console
= NULL
;
3643 if (menu_file
== NULL
|| menu_fp
== NULL
|| mode
== NULL
)
3644 return (BE_ERR_INVAL
);
3646 menu_path
= strdup(menu_file
);
3647 if (menu_path
== NULL
)
3648 return (BE_ERR_NOMEM
);
3650 (void) dirname(menu_path
);
3651 if (*menu_path
== '.') {
3653 return (BE_ERR_BAD_MENU_PATH
);
3655 if (mkdirp(menu_path
,
3656 S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
) == -1 &&
3659 be_print_err(gettext("be_create_menu: Failed to create the %s "
3660 "directory: %s\n"), menu_path
, strerror(errno
));
3661 return (errno_to_be_err(errno
));
3666 * Check to see if this system supports grub
3668 if (be_has_grub()) {
3670 * The grub menu is missing so we need to create it
3671 * and fill in the first few lines.
3673 FILE *temp_fp
= fopen(menu_file
, "a+");
3674 if (temp_fp
== NULL
) {
3676 return (errno_to_be_err(errno
));
3679 if ((console
= be_get_console_prop()) != NULL
) {
3682 * If console is redirected to serial line,
3683 * GRUB splash screen will not be enabled.
3685 if (strncmp(console
, "text", strlen("text")) == 0 ||
3686 strncmp(console
, "graphics",
3687 strlen("graphics")) == 0) {
3689 (void) fprintf(temp_fp
, "%s\n", BE_GRUB_SPLASH
);
3690 (void) fprintf(temp_fp
, "%s\n",
3691 BE_GRUB_FOREGROUND
);
3692 (void) fprintf(temp_fp
, "%s\n",
3693 BE_GRUB_BACKGROUND
);
3694 (void) fprintf(temp_fp
, "%s\n",
3697 be_print_err(gettext("be_create_menu: "
3698 "console on serial line, "
3699 "GRUB splash image will be disabled\n"));
3703 (void) fprintf(temp_fp
, "timeout 30\n");
3704 (void) fclose(temp_fp
);
3708 * The menu file doesn't exist so we need to create a
3711 FILE *temp_fp
= fopen(menu_file
, "w+");
3712 if (temp_fp
== NULL
) {
3714 return (errno_to_be_err(errno
));
3716 (void) fclose(temp_fp
);
3720 * Now we need to add all the BE's back into the the file.
3722 if (_be_list(NULL
, &be_nodes
) == BE_SUCCESS
) {
3723 while (be_nodes
!= NULL
) {
3724 if (strcmp(pool
, be_nodes
->be_rpool
) == 0) {
3725 (void) be_append_menu(be_nodes
->be_node_name
,
3726 be_nodes
->be_rpool
, NULL
, NULL
, NULL
);
3728 if (be_nodes
->be_active_on_boot
) {
3729 be_rpool
= strdup(be_nodes
->be_rpool
);
3730 be_name
= strdup(be_nodes
->be_node_name
);
3733 be_nodes
= be_nodes
->be_next_node
;
3736 be_free_list(be_nodes
);
3739 * Check to see if this system supports grub
3741 if (be_has_grub()) {
3742 int err
= be_change_grub_default(be_name
, be_rpool
);
3743 if (err
!= BE_SUCCESS
)
3746 *menu_fp
= fopen(menu_file
, mode
);
3747 if (*menu_fp
== NULL
)
3748 return (errno_to_be_err(errno
));
3750 return (BE_SUCCESS
);
3754 * Function: be_open_menu
3756 * This function is used it open the menu.lst file. If this
3757 * file does not exist be_create_menu is called to create it
3758 * and the open file pointer is returned. If the file does
3759 * exist it is simply opened using the mode passed in.
3761 * pool - The name of the pool the menu.lst file is on
3762 * menu_file - The name of the file we're opening.
3763 * menu_fp - A pointer to the file pointer of the file we're
3764 * opening. This is also used to pass back the file
3766 * mode - the original mode to be used for opening the menu.lst
3768 * create_menu - If this is true and the menu.lst file does not
3769 * exist we will attempt to re-create it. However
3770 * if it's false the error returned from the fopen
3773 * BE_SUCCESS - Success
3774 * be_errno_t - Failure
3784 boolean_t create_menu
)
3787 boolean_t set_print
= B_FALSE
;
3789 *menu_fp
= fopen(menu_file
, mode
);
3791 if (*menu_fp
== NULL
) {
3792 if (err
== ENOENT
&& create_menu
) {
3793 be_print_err(gettext("be_open_menu: menu.lst "
3794 "file %s does not exist,\n"), menu_file
);
3799 be_print_err(gettext("WARNING: menu.lst "
3800 "file %s does not exist,\n generating "
3801 "a new menu.lst file\n"), menu_file
);
3805 if ((err
= be_create_menu(pool
, menu_file
,
3806 menu_fp
, mode
)) == ENOENT
)
3807 return (BE_ERR_NO_MENU
);
3808 else if (err
!= BE_SUCCESS
)
3810 else if (*menu_fp
== NULL
)
3811 return (BE_ERR_NO_MENU
);
3813 be_print_err(gettext("be_open_menu: failed "
3814 "to open menu.lst file %s\n"), menu_file
);
3816 return (BE_ERR_NO_MENU
);
3818 return (errno_to_be_err(err
));
3821 return (BE_SUCCESS
);