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 2011 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>
58 #include <libbe_priv.h>
60 /* Private function prototypes */
61 static int update_dataset(char *, int, char *, char *, char *);
62 static int _update_vfstab(char *, char *, char *, char *, be_fs_list_data_t
*);
63 static int be_open_menu(char *, char *, FILE **, char *, boolean_t
);
64 static int be_create_menu(char *, char *, FILE **, char *);
65 static char *be_get_auto_name(char *, char *, boolean_t
);
68 * Global error printing
70 boolean_t do_print
= B_FALSE
;
75 typedef struct zone_be_name_cb_data
{
78 } zone_be_name_cb_data_t
;
80 /* ******************************************************************** */
81 /* Public Functions */
82 /* ******************************************************************** */
85 * Function: be_max_avail
86 * Description: Returns the available size for the zfs dataset passed in.
88 * dataset - The dataset we want to get the available space for.
89 * ret - The available size will be returned in this.
91 * The error returned by the zfs get property function.
96 be_max_avail(char *dataset
, uint64_t *ret
)
101 /* Initialize libzfs handle */
103 return (BE_ERR_INIT
);
105 zhp
= zfs_open(g_zfs
, dataset
, ZFS_TYPE_DATASET
);
108 * The zfs_open failed return an error
110 err
= zfs_err_to_be_err(g_zfs
);
112 err
= be_maxsize_avail(zhp
, ret
);
120 * Function: libbe_print_errors
121 * Description: Turns on/off error output for the library.
123 * set_do_print - Boolean that turns library error
124 * printing on or off.
131 libbe_print_errors(boolean_t set_do_print
)
133 do_print
= set_do_print
;
136 /* ******************************************************************** */
137 /* Semi-Private Functions */
138 /* ******************************************************************** */
141 * Function: be_zfs_init
142 * Description: Initializes the libary global libzfs handle.
149 * Semi-private (library wide use only)
156 if ((g_zfs
= libzfs_init()) == NULL
) {
157 be_print_err(gettext("be_zfs_init: failed to initialize ZFS "
166 * Function: be_zfs_fini
167 * Description: Closes the library global libzfs handle if it currently open.
173 * Semi-private (library wide use only)
185 * Function: be_get_defaults
186 * Description: Open defaults and gets be default paramets
188 * defaults - be defaults struct
192 * Semi-private (library wide use only)
195 be_get_defaults(struct be_defaults
*defaults
)
199 defaults
->be_deflt_rpool_container
= B_FALSE
;
200 defaults
->be_deflt_bename_starts_with
[0] = '\0';
202 if ((defp
= defopen_r(BE_DEFAULTS
)) != NULL
) {
203 const char *res
= defread_r(BE_DFLT_BENAME_STARTS
, defp
);
204 if (res
!= NULL
&& res
[0] != NULL
) {
205 (void) strlcpy(defaults
->be_deflt_bename_starts_with
,
206 res
, ZFS_MAXNAMELEN
);
207 defaults
->be_deflt_rpool_container
= B_TRUE
;
214 * Function: be_make_root_ds
215 * Description: Generate string for BE's root dataset given the pool
216 * it lives in and the BE name.
218 * zpool - pointer zpool name.
219 * be_name - pointer to BE name.
220 * be_root_ds - pointer to buffer to return BE root dataset in.
221 * be_root_ds_size - size of be_root_ds
225 * Semi-private (library wide use only)
228 be_make_root_ds(const char *zpool
, const char *be_name
, char *be_root_ds
,
231 struct be_defaults be_defaults
;
232 be_get_defaults(&be_defaults
);
234 if (be_defaults
.be_deflt_rpool_container
)
235 (void) snprintf(be_root_ds
, be_root_ds_size
, "%s/%s", zpool
,
238 (void) snprintf(be_root_ds
, be_root_ds_size
, "%s/%s/%s", zpool
,
239 BE_CONTAINER_DS_NAME
, be_name
);
243 * Function: be_make_container_ds
244 * Description: Generate string for the BE container dataset given a pool name.
246 * zpool - pointer zpool name.
247 * container_ds - pointer to buffer to return BE container
249 * container_ds_size - size of container_ds
253 * Semi-private (library wide use only)
256 be_make_container_ds(const char *zpool
, char *container_ds
,
257 int container_ds_size
)
259 struct be_defaults be_defaults
;
260 be_get_defaults(&be_defaults
);
262 if (be_defaults
.be_deflt_rpool_container
)
263 (void) snprintf(container_ds
, container_ds_size
, "%s", zpool
);
265 (void) snprintf(container_ds
, container_ds_size
, "%s/%s", zpool
,
266 BE_CONTAINER_DS_NAME
);
270 * Function: be_make_name_from_ds
271 * Description: This function takes a dataset name and strips off the
272 * BE container dataset portion from the beginning. The
273 * returned name is allocated in heap storage, so the caller
274 * is responsible for freeing it.
276 * dataset - dataset to get name from.
277 * rc_loc - dataset underwhich the root container dataset lives.
279 * name of dataset relative to BE container dataset.
280 * NULL if dataset is not under a BE root dataset.
282 * Semi-primate (library wide use only)
285 be_make_name_from_ds(const char *dataset
, char *rc_loc
)
287 char ds
[ZFS_MAXNAMELEN
];
290 struct be_defaults be_defaults
;
291 int rlen
= strlen(rc_loc
);
293 be_get_defaults(&be_defaults
);
296 * First token is the location of where the root container dataset
297 * lives; it must match rc_loc.
299 if (strncmp(dataset
, rc_loc
, rlen
) == 0 && dataset
[rlen
] == '/')
300 (void) strlcpy(ds
, dataset
+ rlen
+ 1, sizeof (ds
));
304 if (be_defaults
.be_deflt_rpool_container
) {
305 if ((name
= strdup(ds
)) == NULL
) {
306 be_print_err(gettext("be_make_name_from_ds: "
307 "memory allocation failed\n"));
311 /* Second token must be BE container dataset name */
312 if ((tok
= strtok(ds
, "/")) == NULL
||
313 strcmp(tok
, BE_CONTAINER_DS_NAME
) != 0)
316 /* Return the remaining token if one exists */
317 if ((tok
= strtok(NULL
, "")) == NULL
)
320 if ((name
= strdup(tok
)) == NULL
) {
321 be_print_err(gettext("be_make_name_from_ds: "
322 "memory allocation failed\n"));
331 * Function: be_maxsize_avail
332 * Description: Returns the available size for the zfs handle passed in.
334 * zhp - A pointer to the open zfs handle.
335 * ret - The available size will be returned in this.
337 * The error returned by the zfs get property function.
339 * Semi-private (library wide use only)
342 be_maxsize_avail(zfs_handle_t
*zhp
, uint64_t *ret
)
344 return ((*ret
= zfs_prop_get_int(zhp
, ZFS_PROP_AVAILABLE
)));
348 * Function: be_append_menu
349 * Description: Appends an entry for a BE into the menu.lst.
351 * be_name - pointer to name of BE to add boot menu entry for.
352 * be_root_pool - pointer to name of pool BE lives in.
353 * boot_pool - Used if the pool containing the grub menu is
354 * different than the one contaiing the BE. This
355 * will normally be NULL.
356 * be_orig_root_ds - The root dataset for the BE. This is
357 * used to check to see if an entry already exists
359 * description - pointer to description of BE to be added in
360 * the title line for this BEs entry.
362 * BE_SUCCESS - Success
363 * be_errno_t - Failure
365 * Semi-private (library wide use only)
368 be_append_menu(char *be_name
, char *be_root_pool
, char *boot_pool
,
369 char *be_orig_root_ds
, char *description
)
371 zfs_handle_t
*zhp
= NULL
;
372 char menu_file
[MAXPATHLEN
];
373 char be_root_ds
[MAXPATHLEN
];
375 char temp_line
[BUFSIZ
];
376 char title
[MAXPATHLEN
];
377 char *entries
[BUFSIZ
];
378 char *tmp_entries
[BUFSIZ
];
379 char *pool_mntpnt
= NULL
;
380 char *ptmp_mntpnt
= NULL
;
381 char *orig_mntpnt
= NULL
;
382 boolean_t found_be
= B_FALSE
;
383 boolean_t found_orig_be
= B_FALSE
;
384 boolean_t found_title
= B_FALSE
;
385 boolean_t pool_mounted
= B_FALSE
;
386 boolean_t collect_lines
= B_FALSE
;
387 FILE *menu_fp
= NULL
;
388 int err
= 0, ret
= BE_SUCCESS
;
389 int i
, num_tmp_lines
= 0, num_lines
= 0;
391 if (be_name
== NULL
|| be_root_pool
== NULL
)
392 return (BE_ERR_INVAL
);
394 if (boot_pool
== NULL
)
395 boot_pool
= be_root_pool
;
397 if ((zhp
= zfs_open(g_zfs
, be_root_pool
, ZFS_TYPE_DATASET
)) == NULL
) {
398 be_print_err(gettext("be_append_menu: failed to open "
399 "pool dataset for %s: %s\n"), be_root_pool
,
400 libzfs_error_description(g_zfs
));
401 return (zfs_err_to_be_err(g_zfs
));
405 * Check to see if the pool's dataset is mounted. If it isn't we'll
406 * attempt to mount it.
408 if ((ret
= be_mount_pool(zhp
, &ptmp_mntpnt
, &orig_mntpnt
,
409 &pool_mounted
)) != BE_SUCCESS
) {
410 be_print_err(gettext("be_append_menu: pool dataset "
411 "(%s) could not be mounted\n"), be_root_pool
);
417 * Get the mountpoint for the root pool dataset.
419 if (!zfs_is_mounted(zhp
, &pool_mntpnt
)) {
420 be_print_err(gettext("be_append_menu: pool "
421 "dataset (%s) is not mounted. Can't set "
422 "the default BE in the grub menu.\n"), be_root_pool
);
423 ret
= BE_ERR_NO_MENU
;
428 * Check to see if this system supports grub
431 (void) snprintf(menu_file
, sizeof (menu_file
),
432 "%s%s", pool_mntpnt
, BE_GRUB_MENU
);
434 (void) snprintf(menu_file
, sizeof (menu_file
),
435 "%s%s", pool_mntpnt
, BE_SPARC_MENU
);
438 be_make_root_ds(be_root_pool
, be_name
, be_root_ds
, sizeof (be_root_ds
));
441 * Iterate through menu first to make sure the BE doesn't already
442 * have an entry in the menu.
444 * Additionally while iterating through the menu, if we have an
445 * original root dataset for a BE we're cloning from, we need to keep
446 * track of that BE's menu entry. We will then use the lines from
447 * that entry to create the entry for the new BE.
449 if ((ret
= be_open_menu(be_root_pool
, menu_file
,
450 &menu_fp
, "r", B_TRUE
)) != BE_SUCCESS
) {
452 } else if (menu_fp
== NULL
) {
453 ret
= BE_ERR_NO_MENU
;
460 while (fgets(line
, BUFSIZ
, menu_fp
)) {
463 (void) strlcpy(temp_line
, line
, BUFSIZ
);
464 tok
= strtok(line
, BE_WHITE_SPACE
);
466 if (tok
== NULL
|| tok
[0] == '#') {
468 } else if (strcmp(tok
, "title") == 0) {
469 collect_lines
= B_FALSE
;
470 if ((tok
= strtok(NULL
, "\n")) == NULL
)
471 (void) strlcpy(title
, "", sizeof (title
));
473 (void) strlcpy(title
, tok
, sizeof (title
));
474 found_title
= B_TRUE
;
476 if (num_tmp_lines
!= 0) {
477 for (i
= 0; i
< num_tmp_lines
; i
++) {
478 free(tmp_entries
[i
]);
479 tmp_entries
[i
] = NULL
;
483 } else if (strcmp(tok
, "bootfs") == 0) {
484 char *bootfs
= strtok(NULL
, BE_WHITE_SPACE
);
485 found_title
= B_FALSE
;
489 if (strcmp(bootfs
, be_root_ds
) == 0) {
494 if (be_orig_root_ds
!= NULL
&&
495 strcmp(bootfs
, be_orig_root_ds
) == 0 &&
498 found_orig_be
= B_TRUE
;
501 * Store the new title line
503 (void) snprintf(str
, BUFSIZ
, "title %s\n",
504 description
? description
: be_name
);
505 entries
[num_lines
] = strdup(str
);
508 * If there are any lines between the title
509 * and the bootfs line store these. Also
510 * free the temporary lines.
512 for (i
= 0; i
< num_tmp_lines
; i
++) {
513 entries
[num_lines
] = tmp_entries
[i
];
514 tmp_entries
[i
] = NULL
;
519 * Store the new bootfs line.
521 (void) snprintf(str
, BUFSIZ
, "bootfs %s\n",
523 entries
[num_lines
] = strdup(str
);
525 collect_lines
= B_TRUE
;
527 } else if (found_orig_be
&& collect_lines
) {
529 * get the rest of the lines for the original BE and
532 if (strstr(line
, BE_GRUB_COMMENT
) != NULL
||
533 strstr(line
, "BOOTADM") != NULL
)
535 if (strcmp(tok
, "splashimage") == 0) {
537 strdup("splashimage "
538 "/boot/splashimage.xpm\n");
540 entries
[num_lines
] = strdup(temp_line
);
543 } else if (found_title
&& !found_orig_be
) {
544 tmp_entries
[num_tmp_lines
] = strdup(temp_line
);
549 (void) fclose(menu_fp
);
553 * If an entry for this BE was already in the menu, then if
554 * that entry's title matches what we would have put in
555 * return success. Otherwise return failure.
557 char *new_title
= description
? description
: be_name
;
559 if (strcmp(title
, new_title
) == 0) {
563 if (be_remove_menu(be_name
, be_root_pool
,
564 boot_pool
) != BE_SUCCESS
) {
565 be_print_err(gettext("be_append_menu: "
566 "Failed to remove existing unusable "
567 "entry '%s' in boot menu.\n"), be_name
);
568 ret
= BE_ERR_BE_EXISTS
;
574 /* Append BE entry to the end of the file */
575 menu_fp
= fopen(menu_file
, "a+");
577 if (menu_fp
== NULL
) {
578 be_print_err(gettext("be_append_menu: failed "
579 "to open menu.lst file %s\n"), menu_file
);
580 ret
= errno_to_be_err(err
);
586 * write out all the stored lines
588 for (i
= 0; i
< num_lines
; i
++) {
589 (void) fprintf(menu_fp
, "%s", entries
[i
]);
595 * Check to see if this system supports grub
598 (void) fprintf(menu_fp
, "%s\n", BE_GRUB_COMMENT
);
601 (void) fprintf(menu_fp
, "title %s\n",
602 description
? description
: be_name
);
603 (void) fprintf(menu_fp
, "bootfs %s\n", be_root_ds
);
606 * Check to see if this system supports grub
609 (void) fprintf(menu_fp
, "kernel$ "
610 "/platform/i86pc/kernel/$ISADIR/unix -B "
612 (void) fprintf(menu_fp
, "module$ "
613 "/platform/i86pc/$ISADIR/boot_archive\n");
614 (void) fprintf(menu_fp
, "%s\n", BE_GRUB_COMMENT
);
618 (void) fclose(menu_fp
);
621 int err
= BE_SUCCESS
;
622 err
= be_unmount_pool(zhp
, ptmp_mntpnt
, orig_mntpnt
);
623 if (ret
== BE_SUCCESS
)
629 if (num_tmp_lines
> 0) {
630 for (i
= 0; i
< num_tmp_lines
; i
++) {
631 free(tmp_entries
[i
]);
632 tmp_entries
[i
] = NULL
;
636 for (i
= 0; i
< num_lines
; i
++) {
645 * Function: be_remove_menu
646 * Description: Removes a BE's entry from a menu.lst file.
648 * be_name - the name of BE whose entry is to be removed from
650 * be_root_pool - the pool that be_name lives in.
651 * boot_pool - the pool where the BE is, if different than
652 * the pool containing the boot menu. If this is
653 * NULL it will be set to be_root_pool.
655 * BE_SUCCESS - Success
656 * be_errno_t - Failure
658 * Semi-private (library wide use only)
661 be_remove_menu(char *be_name
, char *be_root_pool
, char *boot_pool
)
663 zfs_handle_t
*zhp
= NULL
;
664 char be_root_ds
[MAXPATHLEN
];
665 char **buffer
= NULL
;
666 char menu_buf
[BUFSIZ
];
667 char menu
[MAXPATHLEN
];
668 char *pool_mntpnt
= NULL
;
669 char *ptmp_mntpnt
= NULL
;
670 char *orig_mntpnt
= NULL
;
671 char *tmp_menu
= NULL
;
672 FILE *menu_fp
= NULL
;
673 FILE *tmp_menu_fp
= NULL
;
675 int ret
= BE_SUCCESS
;
680 int default_entry
= 0;
683 int num_entry_del
= 0;
684 int tmp_menu_len
= 0;
685 boolean_t write
= B_TRUE
;
686 boolean_t do_buffer
= B_FALSE
;
687 boolean_t pool_mounted
= B_FALSE
;
689 if (boot_pool
== NULL
)
690 boot_pool
= be_root_pool
;
692 /* Get name of BE's root dataset */
693 be_make_root_ds(be_root_pool
, be_name
, be_root_ds
, sizeof (be_root_ds
));
695 /* Get handle to pool dataset */
696 if ((zhp
= zfs_open(g_zfs
, be_root_pool
, ZFS_TYPE_DATASET
)) == NULL
) {
697 be_print_err(gettext("be_remove_menu: "
698 "failed to open pool dataset for %s: %s"),
699 be_root_pool
, libzfs_error_description(g_zfs
));
700 return (zfs_err_to_be_err(g_zfs
));
704 * Check to see if the pool's dataset is mounted. If it isn't we'll
705 * attempt to mount it.
707 if ((ret
= be_mount_pool(zhp
, &ptmp_mntpnt
, &orig_mntpnt
,
708 &pool_mounted
)) != BE_SUCCESS
) {
709 be_print_err(gettext("be_remove_menu: pool dataset "
710 "(%s) could not be mounted\n"), be_root_pool
);
716 * Get the mountpoint for the root pool dataset.
718 if (!zfs_is_mounted(zhp
, &pool_mntpnt
)) {
719 be_print_err(gettext("be_remove_menu: pool "
720 "dataset (%s) is not mounted. Can't set "
721 "the default BE in the grub menu.\n"), be_root_pool
);
722 ret
= BE_ERR_NO_MENU
;
726 /* Get path to boot menu */
727 (void) strlcpy(menu
, pool_mntpnt
, sizeof (menu
));
730 * Check to see if this system supports grub
733 (void) strlcat(menu
, BE_GRUB_MENU
, sizeof (menu
));
735 (void) strlcat(menu
, BE_SPARC_MENU
, sizeof (menu
));
737 /* Get handle to boot menu file */
738 if ((ret
= be_open_menu(be_root_pool
, menu
, &menu_fp
, "r",
739 B_TRUE
)) != BE_SUCCESS
) {
741 } else if (menu_fp
== NULL
) {
742 ret
= BE_ERR_NO_MENU
;
749 /* Grab the stats of the original menu file */
750 if (stat(menu
, &sb
) != 0) {
752 be_print_err(gettext("be_remove_menu: "
753 "failed to stat file %s: %s\n"), menu
, strerror(err
));
754 ret
= errno_to_be_err(err
);
758 /* Create a tmp file for the modified menu.lst */
759 tmp_menu_len
= strlen(menu
) + 7;
760 if ((tmp_menu
= (char *)malloc(tmp_menu_len
)) == NULL
) {
761 be_print_err(gettext("be_remove_menu: malloc failed\n"));
765 (void) memset(tmp_menu
, 0, tmp_menu_len
);
766 (void) strlcpy(tmp_menu
, menu
, tmp_menu_len
);
767 (void) strlcat(tmp_menu
, "XXXXXX", tmp_menu_len
);
768 if ((fd
= mkstemp(tmp_menu
)) == -1) {
770 be_print_err(gettext("be_remove_menu: mkstemp failed\n"));
771 ret
= errno_to_be_err(err
);
776 if ((tmp_menu_fp
= fdopen(fd
, "w")) == NULL
) {
778 be_print_err(gettext("be_remove_menu: "
779 "could not open tmp file for write: %s\n"), strerror(err
));
781 ret
= errno_to_be_err(err
);
785 while (fgets(menu_buf
, BUFSIZ
, menu_fp
)) {
789 (void) strlcpy(tline
, menu_buf
, sizeof (tline
));
792 tok
= strtok(tline
, BE_WHITE_SPACE
);
794 if (tok
== NULL
|| tok
[0] == '#') {
795 /* Found empty line or comment line */
797 /* Buffer this line */
798 if ((buffer
= (char **)realloc(buffer
,
799 sizeof (char *)*(nlines
+ 1))) == NULL
) {
803 if ((buffer
[nlines
++] = strdup(menu_buf
))
809 } else if (write
|| strncmp(menu_buf
, BE_GRUB_COMMENT
,
810 strlen(BE_GRUB_COMMENT
)) != 0) {
811 /* Write this line out */
812 (void) fputs(menu_buf
, tmp_menu_fp
);
814 } else if (strcmp(tok
, "default") == 0) {
816 * Record what 'default' is set to because we might
817 * need to adjust this upon deleting an entry.
819 tok
= strtok(NULL
, BE_WHITE_SPACE
);
822 default_entry
= atoi(tok
);
825 (void) fputs(menu_buf
, tmp_menu_fp
);
826 } else if (strcmp(tok
, "title") == 0) {
828 * If we've reached a 'title' line and do_buffer is
829 * is true, that means we've just buffered an entire
830 * entry without finding a 'bootfs' directive. We
831 * need to write that entry out and keep searching.
834 for (i
= 0; i
< nlines
; i
++) {
835 (void) fputs(buffer
[i
], tmp_menu_fp
);
844 * Turn writing off and buffering on, and increment
851 /* Buffer this 'title' line */
852 if ((buffer
= (char **)realloc(buffer
,
853 sizeof (char *)*(nlines
+ 1))) == NULL
) {
857 if ((buffer
[nlines
++] = strdup(menu_buf
)) == NULL
) {
862 } else if (strcmp(tok
, "bootfs") == 0) {
866 * Found a 'bootfs' line. See if it matches the
867 * BE we're looking for.
869 if ((bootfs
= strtok(NULL
, BE_WHITE_SPACE
)) == NULL
||
870 strcmp(bootfs
, be_root_ds
) != 0) {
872 * Either there's nothing after the 'bootfs'
873 * or this is not the BE we're looking for,
874 * write out the line(s) we've buffered since
877 for (i
= 0; i
< nlines
; i
++) {
878 (void) fputs(buffer
[i
], tmp_menu_fp
);
886 * Turn writing back on, and turn off buffering
887 * since this isn't the entry we're looking
893 /* Write this 'bootfs' line out. */
894 (void) fputs(menu_buf
, tmp_menu_fp
);
897 * Found the entry we're looking for.
898 * Record its entry number, increment the
899 * number of entries we've deleted, and turn
900 * writing off. Also, throw away the lines
901 * we've buffered for this entry so far, we
904 entry_del
= entry_cnt
- 1;
909 for (i
= 0; i
< nlines
; i
++) {
918 /* Buffer this line */
919 if ((buffer
= (char **)realloc(buffer
,
920 sizeof (char *)*(nlines
+ 1))) == NULL
) {
924 if ((buffer
[nlines
++] = strdup(menu_buf
))
930 /* Write this line out */
931 (void) fputs(menu_buf
, tmp_menu_fp
);
936 (void) fclose(menu_fp
);
938 (void) fclose(tmp_menu_fp
);
941 /* Copy the modified menu.lst into place */
942 if (rename(tmp_menu
, menu
) != 0) {
944 be_print_err(gettext("be_remove_menu: "
945 "failed to rename file %s to %s: %s\n"),
946 tmp_menu
, menu
, strerror(err
));
947 ret
= errno_to_be_err(err
);
954 * If we've removed an entry, see if we need to
955 * adjust the default value in the menu.lst. If the
956 * entry we've deleted comes before the default entry
957 * we need to adjust the default value accordingly.
959 * be_has_grub is used here to check to see if this system
962 if (be_has_grub() && num_entry_del
> 0) {
963 if (entry_del
<= default_entry
) {
964 default_entry
= default_entry
- num_entry_del
;
965 if (default_entry
< 0)
969 * Adjust the default value by rewriting the
970 * menu.lst file. This may be overkill, but to
971 * preserve the location of the 'default' entry
972 * in the file, we need to do this.
975 /* Get handle to boot menu file */
976 if ((menu_fp
= fopen(menu
, "r")) == NULL
) {
978 be_print_err(gettext("be_remove_menu: "
979 "failed to open menu.lst (%s): %s\n"),
980 menu
, strerror(err
));
981 ret
= errno_to_be_err(err
);
985 /* Create a tmp file for the modified menu.lst */
986 tmp_menu_len
= strlen(menu
) + 7;
987 if ((tmp_menu
= (char *)malloc(tmp_menu_len
))
989 be_print_err(gettext("be_remove_menu: "
994 (void) memset(tmp_menu
, 0, tmp_menu_len
);
995 (void) strlcpy(tmp_menu
, menu
, tmp_menu_len
);
996 (void) strlcat(tmp_menu
, "XXXXXX", tmp_menu_len
);
997 if ((fd
= mkstemp(tmp_menu
)) == -1) {
999 be_print_err(gettext("be_remove_menu: "
1000 "mkstemp failed: %s\n"), strerror(err
));
1001 ret
= errno_to_be_err(err
);
1006 if ((tmp_menu_fp
= fdopen(fd
, "w")) == NULL
) {
1008 be_print_err(gettext("be_remove_menu: "
1009 "could not open tmp file for write: %s\n"),
1012 ret
= errno_to_be_err(err
);
1016 while (fgets(menu_buf
, BUFSIZ
, menu_fp
)) {
1017 char tline
[BUFSIZ
];
1020 (void) strlcpy(tline
, menu_buf
, sizeof (tline
));
1023 tok
= strtok(tline
, BE_WHITE_SPACE
);
1026 /* Found empty line, write it out */
1027 (void) fputs(menu_buf
, tmp_menu_fp
);
1028 } else if (strcmp(tok
, "default") == 0) {
1029 /* Found the default line, adjust it */
1030 (void) snprintf(tline
, sizeof (tline
),
1031 "default %d\n", default_entry
);
1033 (void) fputs(tline
, tmp_menu_fp
);
1035 /* Pass through all other lines */
1036 (void) fputs(menu_buf
, tmp_menu_fp
);
1040 (void) fclose(menu_fp
);
1042 (void) fclose(tmp_menu_fp
);
1045 /* Copy the modified menu.lst into place */
1046 if (rename(tmp_menu
, menu
) != 0) {
1048 be_print_err(gettext("be_remove_menu: "
1049 "failed to rename file %s to %s: %s\n"),
1050 tmp_menu
, menu
, strerror(err
));
1051 ret
= errno_to_be_err(err
);
1060 /* Set the perms and ownership of the updated file */
1061 if (chmod(menu
, sb
.st_mode
) != 0) {
1063 be_print_err(gettext("be_remove_menu: "
1064 "failed to chmod %s: %s\n"), menu
, strerror(err
));
1065 ret
= errno_to_be_err(err
);
1068 if (chown(menu
, sb
.st_uid
, sb
.st_gid
) != 0) {
1070 be_print_err(gettext("be_remove_menu: "
1071 "failed to chown %s: %s\n"), menu
, strerror(err
));
1072 ret
= errno_to_be_err(err
);
1078 int err
= BE_SUCCESS
;
1079 err
= be_unmount_pool(zhp
, ptmp_mntpnt
, orig_mntpnt
);
1080 if (ret
== BE_SUCCESS
)
1088 if (menu_fp
!= NULL
)
1089 (void) fclose(menu_fp
);
1090 if (tmp_menu_fp
!= NULL
)
1091 (void) fclose(tmp_menu_fp
);
1092 if (tmp_menu
!= NULL
) {
1093 (void) unlink(tmp_menu
);
1101 * Function: be_default_grub_bootfs
1102 * Description: This function returns the dataset in the default entry of
1103 * the grub menu. If no default entry is found with a valid bootfs
1104 * entry NULL is returned.
1106 * be_root_pool - This is the name of the root pool where the
1107 * grub menu can be found.
1108 * def_bootfs - This is used to pass back the bootfs string. On
1109 * error NULL is returned here.
1111 * Success - BE_SUCCESS is returned.
1112 * Failure - a be_errno_t is returned.
1114 * Semi-private (library wide use only)
1117 be_default_grub_bootfs(const char *be_root_pool
, char **def_bootfs
)
1119 zfs_handle_t
*zhp
= NULL
;
1120 char grub_file
[MAXPATHLEN
];
1123 char *pool_mntpnt
= NULL
;
1124 char *ptmp_mntpnt
= NULL
;
1125 char *orig_mntpnt
= NULL
;
1126 int default_entry
= 0, entries
= 0;
1127 int found_default
= 0;
1128 int ret
= BE_SUCCESS
;
1129 boolean_t pool_mounted
= B_FALSE
;
1134 * Check to see if this system supports grub
1136 if (!be_has_grub()) {
1137 be_print_err(gettext("be_default_grub_bootfs: operation "
1138 "not supported on this architecture\n"));
1139 return (BE_ERR_NOTSUP
);
1144 /* Get handle to pool dataset */
1145 if ((zhp
= zfs_open(g_zfs
, be_root_pool
, ZFS_TYPE_DATASET
)) == NULL
) {
1146 be_print_err(gettext("be_default_grub_bootfs: "
1147 "failed to open pool dataset for %s: %s"),
1148 be_root_pool
, libzfs_error_description(g_zfs
));
1149 return (zfs_err_to_be_err(g_zfs
));
1153 * Check to see if the pool's dataset is mounted. If it isn't we'll
1154 * attempt to mount it.
1156 if ((ret
= be_mount_pool(zhp
, &ptmp_mntpnt
, &orig_mntpnt
,
1157 &pool_mounted
)) != BE_SUCCESS
) {
1158 be_print_err(gettext("be_default_grub_bootfs: pool dataset "
1159 "(%s) could not be mounted\n"), be_root_pool
);
1165 * Get the mountpoint for the root pool dataset.
1167 if (!zfs_is_mounted(zhp
, &pool_mntpnt
)) {
1168 be_print_err(gettext("be_default_grub_bootfs: failed "
1169 "to get mount point for the root pool. Can't set "
1170 "the default BE in the grub menu.\n"));
1171 ret
= BE_ERR_NO_MENU
;
1175 (void) snprintf(grub_file
, MAXPATHLEN
, "%s%s",
1176 pool_mntpnt
, BE_GRUB_MENU
);
1178 if ((ret
= be_open_menu((char *)be_root_pool
, grub_file
,
1179 &menu_fp
, "r", B_FALSE
)) != BE_SUCCESS
) {
1181 } else if (menu_fp
== NULL
) {
1182 ret
= BE_ERR_NO_MENU
;
1189 while (fgets(line
, BUFSIZ
, menu_fp
)) {
1190 char *tok
= strtok(line
, BE_WHITE_SPACE
);
1192 if (tok
!= NULL
&& tok
[0] != '#') {
1193 if (!found_default
) {
1194 if (strcmp(tok
, "default") == 0) {
1195 tok
= strtok(NULL
, BE_WHITE_SPACE
);
1197 default_entry
= atoi(tok
);
1204 if (strcmp(tok
, "title") == 0) {
1206 } else if (default_entry
== entries
- 1) {
1207 if (strcmp(tok
, "bootfs") == 0) {
1208 tok
= strtok(NULL
, BE_WHITE_SPACE
);
1209 (void) fclose(menu_fp
);
1216 if ((*def_bootfs
= strdup(tok
)) !=
1221 be_print_err(gettext(
1222 "be_default_grub_bootfs: "
1223 "memory allocation failed\n"));
1227 } else if (default_entry
< entries
- 1) {
1229 * no bootfs entry for the default entry.
1235 (void) fclose(menu_fp
);
1239 int err
= BE_SUCCESS
;
1240 err
= be_unmount_pool(zhp
, ptmp_mntpnt
, orig_mntpnt
);
1241 if (ret
== BE_SUCCESS
)
1251 * Function: be_change_grub_default
1252 * Description: This function takes two parameters. These are the name of
1253 * the BE we want to have as the default booted in the grub
1254 * menu and the root pool where the path to the grub menu exists.
1255 * The code takes this and finds the BE's entry in the grub menu
1256 * and changes the default entry to point to that entry in the
1259 * be_name - This is the name of the BE wanted as the default
1260 * for the next boot.
1261 * be_root_pool - This is the name of the root pool where the
1262 * grub menu can be found.
1264 * BE_SUCCESS - Success
1265 * be_errno_t - Failure
1267 * Semi-private (library wide use only)
1270 be_change_grub_default(char *be_name
, char *be_root_pool
)
1272 zfs_handle_t
*zhp
= NULL
;
1273 char grub_file
[MAXPATHLEN
];
1275 char *pool_mntpnt
= NULL
;
1276 char *ptmp_mntpnt
= NULL
;
1277 char *orig_mntpnt
= NULL
;
1279 char temp_line
[BUFSIZ
];
1280 char be_root_ds
[MAXPATHLEN
];
1281 FILE *grub_fp
= NULL
;
1282 FILE *temp_fp
= NULL
;
1284 int temp_grub_len
= 0;
1285 int fd
, entries
= 0;
1287 int ret
= BE_SUCCESS
;
1288 boolean_t found_default
= B_FALSE
;
1289 boolean_t pool_mounted
= B_FALSE
;
1294 * Check to see if this system supports grub
1296 if (!be_has_grub()) {
1297 be_print_err(gettext("be_change_grub_default: operation "
1298 "not supported on this architecture\n"));
1299 return (BE_ERR_NOTSUP
);
1302 /* Generate string for BE's root dataset */
1303 be_make_root_ds(be_root_pool
, be_name
, be_root_ds
, sizeof (be_root_ds
));
1305 /* Get handle to pool dataset */
1306 if ((zhp
= zfs_open(g_zfs
, be_root_pool
, ZFS_TYPE_DATASET
)) == NULL
) {
1307 be_print_err(gettext("be_change_grub_default: "
1308 "failed to open pool dataset for %s: %s"),
1309 be_root_pool
, libzfs_error_description(g_zfs
));
1310 return (zfs_err_to_be_err(g_zfs
));
1314 * Check to see if the pool's dataset is mounted. If it isn't we'll
1315 * attempt to mount it.
1317 if ((ret
= be_mount_pool(zhp
, &ptmp_mntpnt
, &orig_mntpnt
,
1318 &pool_mounted
)) != BE_SUCCESS
) {
1319 be_print_err(gettext("be_change_grub_default: pool dataset "
1320 "(%s) could not be mounted\n"), be_root_pool
);
1326 * Get the mountpoint for the root pool dataset.
1328 if (!zfs_is_mounted(zhp
, &pool_mntpnt
)) {
1329 be_print_err(gettext("be_change_grub_default: pool "
1330 "dataset (%s) is not mounted. Can't set "
1331 "the default BE in the grub menu.\n"), be_root_pool
);
1332 ret
= BE_ERR_NO_MENU
;
1336 (void) snprintf(grub_file
, MAXPATHLEN
, "%s%s",
1337 pool_mntpnt
, BE_GRUB_MENU
);
1339 if ((ret
= be_open_menu(be_root_pool
, grub_file
,
1340 &grub_fp
, "r+", B_TRUE
)) != BE_SUCCESS
) {
1342 } else if (grub_fp
== NULL
) {
1343 ret
= BE_ERR_NO_MENU
;
1350 /* Grab the stats of the original menu file */
1351 if (stat(grub_file
, &sb
) != 0) {
1353 be_print_err(gettext("be_change_grub_default: "
1354 "failed to stat file %s: %s\n"), grub_file
, strerror(err
));
1355 ret
= errno_to_be_err(err
);
1359 /* Create a tmp file for the modified menu.lst */
1360 temp_grub_len
= strlen(grub_file
) + 7;
1361 if ((temp_grub
= (char *)malloc(temp_grub_len
)) == NULL
) {
1362 be_print_err(gettext("be_change_grub_default: "
1363 "malloc failed\n"));
1367 (void) memset(temp_grub
, 0, temp_grub_len
);
1368 (void) strlcpy(temp_grub
, grub_file
, temp_grub_len
);
1369 (void) strlcat(temp_grub
, "XXXXXX", temp_grub_len
);
1370 if ((fd
= mkstemp(temp_grub
)) == -1) {
1372 be_print_err(gettext("be_change_grub_default: "
1373 "mkstemp failed: %s\n"), strerror(err
));
1374 ret
= errno_to_be_err(err
);
1379 if ((temp_fp
= fdopen(fd
, "w")) == NULL
) {
1381 be_print_err(gettext("be_change_grub_default: "
1382 "failed to open %s file: %s\n"),
1383 temp_grub
, strerror(err
));
1385 ret
= errno_to_be_err(err
);
1389 while (fgets(line
, BUFSIZ
, grub_fp
)) {
1390 char *tok
= strtok(line
, BE_WHITE_SPACE
);
1392 if (tok
== NULL
|| tok
[0] == '#') {
1394 } else if (strcmp(tok
, "title") == 0) {
1397 } else if (strcmp(tok
, "bootfs") == 0) {
1398 char *bootfs
= strtok(NULL
, BE_WHITE_SPACE
);
1402 if (strcmp(bootfs
, be_root_ds
) == 0) {
1403 found_default
= B_TRUE
;
1409 if (!found_default
) {
1410 be_print_err(gettext("be_change_grub_default: failed "
1411 "to find entry for %s in the grub menu\n"),
1413 ret
= BE_ERR_BE_NOENT
;
1419 while (fgets(line
, BUFSIZ
, grub_fp
)) {
1422 (void) strncpy(temp_line
, line
, BUFSIZ
);
1424 if ((tok
= strtok(temp_line
, BE_WHITE_SPACE
)) != NULL
&&
1425 strcmp(tok
, "default") == 0) {
1426 (void) snprintf(temp_line
, BUFSIZ
, "default %d\n",
1427 entries
- 1 >= 0 ? entries
- 1 : 0);
1428 (void) fputs(temp_line
, temp_fp
);
1430 (void) fputs(line
, temp_fp
);
1434 (void) fclose(grub_fp
);
1436 (void) fclose(temp_fp
);
1439 if (rename(temp_grub
, grub_file
) != 0) {
1441 be_print_err(gettext("be_change_grub_default: "
1442 "failed to rename file %s to %s: %s\n"),
1443 temp_grub
, grub_file
, strerror(err
));
1444 ret
= errno_to_be_err(err
);
1450 /* Set the perms and ownership of the updated file */
1451 if (chmod(grub_file
, sb
.st_mode
) != 0) {
1453 be_print_err(gettext("be_change_grub_default: "
1454 "failed to chmod %s: %s\n"), grub_file
, strerror(err
));
1455 ret
= errno_to_be_err(err
);
1458 if (chown(grub_file
, sb
.st_uid
, sb
.st_gid
) != 0) {
1460 be_print_err(gettext("be_change_grub_default: "
1461 "failed to chown %s: %s\n"), grub_file
, strerror(err
));
1462 ret
= errno_to_be_err(err
);
1467 int err
= BE_SUCCESS
;
1468 err
= be_unmount_pool(zhp
, ptmp_mntpnt
, orig_mntpnt
);
1469 if (ret
== BE_SUCCESS
)
1475 if (grub_fp
!= NULL
)
1476 (void) fclose(grub_fp
);
1477 if (temp_fp
!= NULL
)
1478 (void) fclose(temp_fp
);
1479 if (temp_grub
!= NULL
) {
1480 (void) unlink(temp_grub
);
1488 * Function: be_update_menu
1489 * Description: This function is used by be_rename to change the BE name in
1490 * an existing entry in the grub menu to the new name of the BE.
1492 * be_orig_name - the original name of the BE
1493 * be_new_name - the new name the BE is being renameed to.
1494 * be_root_pool - The pool which contains the grub menu
1495 * boot_pool - the pool where the BE is, if different than
1496 * the pool containing the boot menu. If this is
1497 * NULL it will be set to be_root_pool.
1499 * BE_SUCCESS - Success
1500 * be_errno_t - Failure
1502 * Semi-private (library wide use only)
1505 be_update_menu(char *be_orig_name
, char *be_new_name
, char *be_root_pool
,
1508 zfs_handle_t
*zhp
= NULL
;
1509 char menu_file
[MAXPATHLEN
];
1510 char be_root_ds
[MAXPATHLEN
];
1511 char be_new_root_ds
[MAXPATHLEN
];
1513 char *pool_mntpnt
= NULL
;
1514 char *ptmp_mntpnt
= NULL
;
1515 char *orig_mntpnt
= NULL
;
1516 char *temp_menu
= NULL
;
1517 FILE *menu_fp
= NULL
;
1518 FILE *new_fp
= NULL
;
1520 int temp_menu_len
= 0;
1522 int ret
= BE_SUCCESS
;
1524 boolean_t pool_mounted
= B_FALSE
;
1528 if (boot_pool
== NULL
)
1529 boot_pool
= be_root_pool
;
1531 if ((zhp
= zfs_open(g_zfs
, be_root_pool
, ZFS_TYPE_DATASET
)) == NULL
) {
1532 be_print_err(gettext("be_update_menu: failed to open "
1533 "pool dataset for %s: %s\n"), be_root_pool
,
1534 libzfs_error_description(g_zfs
));
1535 return (zfs_err_to_be_err(g_zfs
));
1539 * Check to see if the pool's dataset is mounted. If it isn't we'll
1540 * attempt to mount it.
1542 if ((ret
= be_mount_pool(zhp
, &ptmp_mntpnt
, &orig_mntpnt
,
1543 &pool_mounted
)) != BE_SUCCESS
) {
1544 be_print_err(gettext("be_update_menu: pool dataset "
1545 "(%s) could not be mounted\n"), be_root_pool
);
1551 * Get the mountpoint for the root pool dataset.
1553 if (!zfs_is_mounted(zhp
, &pool_mntpnt
)) {
1554 be_print_err(gettext("be_update_menu: failed "
1555 "to get mount point for the root pool. Can't set "
1556 "the default BE in the grub menu.\n"));
1557 ret
= BE_ERR_NO_MENU
;
1562 * Check to see if this system supports grub
1564 if (be_has_grub()) {
1565 (void) snprintf(menu_file
, sizeof (menu_file
),
1566 "%s%s", pool_mntpnt
, BE_GRUB_MENU
);
1568 (void) snprintf(menu_file
, sizeof (menu_file
),
1569 "%s%s", pool_mntpnt
, BE_SPARC_MENU
);
1572 be_make_root_ds(be_root_pool
, be_orig_name
, be_root_ds
,
1573 sizeof (be_root_ds
));
1574 be_make_root_ds(be_root_pool
, be_new_name
, be_new_root_ds
,
1575 sizeof (be_new_root_ds
));
1577 if ((ret
= be_open_menu(be_root_pool
, menu_file
,
1578 &menu_fp
, "r", B_TRUE
)) != BE_SUCCESS
) {
1580 } else if (menu_fp
== NULL
) {
1581 ret
= BE_ERR_NO_MENU
;
1588 /* Grab the stat of the original menu file */
1589 if (stat(menu_file
, &sb
) != 0) {
1591 be_print_err(gettext("be_update_menu: "
1592 "failed to stat file %s: %s\n"), menu_file
, strerror(err
));
1593 (void) fclose(menu_fp
);
1594 ret
= errno_to_be_err(err
);
1598 /* Create tmp file for modified menu.lst */
1599 temp_menu_len
= strlen(menu_file
) + 7;
1600 if ((temp_menu
= (char *)malloc(temp_menu_len
))
1602 be_print_err(gettext("be_update_menu: "
1603 "malloc failed\n"));
1604 (void) fclose(menu_fp
);
1608 (void) memset(temp_menu
, 0, temp_menu_len
);
1609 (void) strlcpy(temp_menu
, menu_file
, temp_menu_len
);
1610 (void) strlcat(temp_menu
, "XXXXXX", temp_menu_len
);
1611 if ((tmp_fd
= mkstemp(temp_menu
)) == -1) {
1613 be_print_err(gettext("be_update_menu: "
1614 "mkstemp failed: %s\n"), strerror(err
));
1615 (void) fclose(menu_fp
);
1617 ret
= errno_to_be_err(err
);
1620 if ((new_fp
= fdopen(tmp_fd
, "w")) == NULL
) {
1622 be_print_err(gettext("be_update_menu: "
1623 "fdopen failed: %s\n"), strerror(err
));
1624 (void) close(tmp_fd
);
1625 (void) fclose(menu_fp
);
1627 ret
= errno_to_be_err(err
);
1631 while (fgets(line
, BUFSIZ
, menu_fp
)) {
1633 char new_line
[BUFSIZ
];
1636 (void) strlcpy(tline
, line
, sizeof (tline
));
1639 c
= strtok(tline
, BE_WHITE_SPACE
);
1642 /* Found empty line, write it out. */
1643 (void) fputs(line
, new_fp
);
1644 } else if (c
[0] == '#') {
1645 /* Found a comment line, write it out. */
1646 (void) fputs(line
, new_fp
);
1647 } else if (strcmp(c
, "title") == 0) {
1652 * Found a 'title' line, parse out BE name or
1655 name
= strtok(NULL
, BE_WHITE_SPACE
);
1659 * Nothing after 'title', just push
1662 (void) fputs(line
, new_fp
);
1665 * Grab the remainder of the title which
1666 * could be a multi worded description
1668 desc
= strtok(NULL
, "\n");
1670 if (strcmp(name
, be_orig_name
) == 0) {
1672 * The first token of the title is
1673 * the old BE name, replace it with
1674 * the new one, and write it out
1675 * along with the remainder of
1676 * description if there is one.
1679 (void) snprintf(new_line
,
1684 (void) snprintf(new_line
,
1686 "title %s\n", be_new_name
);
1689 (void) fputs(new_line
, new_fp
);
1691 (void) fputs(line
, new_fp
);
1694 } else if (strcmp(c
, "bootfs") == 0) {
1696 * Found a 'bootfs' line, parse out the BE root
1699 char *root_ds
= strtok(NULL
, BE_WHITE_SPACE
);
1701 if (root_ds
== NULL
) {
1703 * Nothing after 'bootfs', just push
1706 (void) fputs(line
, new_fp
);
1709 * If this bootfs is the one we're renaming,
1710 * write out the new root dataset value
1712 if (strcmp(root_ds
, be_root_ds
) == 0) {
1713 (void) snprintf(new_line
,
1714 sizeof (new_line
), "bootfs %s\n",
1717 (void) fputs(new_line
, new_fp
);
1719 (void) fputs(line
, new_fp
);
1724 * Found some other line we don't care
1725 * about, write it out.
1727 (void) fputs(line
, new_fp
);
1731 (void) fclose(menu_fp
);
1732 (void) fclose(new_fp
);
1733 (void) close(tmp_fd
);
1735 if (rename(temp_menu
, menu_file
) != 0) {
1737 be_print_err(gettext("be_update_menu: "
1738 "failed to rename file %s to %s: %s\n"),
1739 temp_menu
, menu_file
, strerror(err
));
1740 ret
= errno_to_be_err(err
);
1744 /* Set the perms and ownership of the updated file */
1745 if (chmod(menu_file
, sb
.st_mode
) != 0) {
1747 be_print_err(gettext("be_update_menu: "
1748 "failed to chmod %s: %s\n"), menu_file
, strerror(err
));
1749 ret
= errno_to_be_err(err
);
1752 if (chown(menu_file
, sb
.st_uid
, sb
.st_gid
) != 0) {
1754 be_print_err(gettext("be_update_menu: "
1755 "failed to chown %s: %s\n"), menu_file
, strerror(err
));
1756 ret
= errno_to_be_err(err
);
1761 int err
= BE_SUCCESS
;
1762 err
= be_unmount_pool(zhp
, ptmp_mntpnt
, orig_mntpnt
);
1763 if (ret
== BE_SUCCESS
)
1773 * Function: be_has_menu_entry
1774 * Description: Checks to see if the BEs root dataset has an entry in the grub
1777 * be_dataset - The root dataset of the BE
1778 * be_root_pool - The pool which contains the boot menu
1779 * entry - A pointer the the entry number of the BE if found.
1784 * Semi-private (library wide use only)
1787 be_has_menu_entry(char *be_dataset
, char *be_root_pool
, int *entry
)
1789 zfs_handle_t
*zhp
= NULL
;
1790 char menu_file
[MAXPATHLEN
];
1794 char *rpool_mntpnt
= NULL
;
1795 char *ptmp_mntpnt
= NULL
;
1796 char *orig_mntpnt
= NULL
;
1799 boolean_t pool_mounted
= B_FALSE
;
1803 * Check to see if this system supports grub
1805 if ((zhp
= zfs_open(g_zfs
, be_root_pool
, ZFS_TYPE_DATASET
)) == NULL
) {
1806 be_print_err(gettext("be_has_menu_entry: failed to open "
1807 "pool dataset for %s: %s\n"), be_root_pool
,
1808 libzfs_error_description(g_zfs
));
1813 * Check to see if the pool's dataset is mounted. If it isn't we'll
1814 * attempt to mount it.
1816 if (be_mount_pool(zhp
, &ptmp_mntpnt
, &orig_mntpnt
,
1817 &pool_mounted
) != 0) {
1818 be_print_err(gettext("be_has_menu_entry: pool dataset "
1819 "(%s) could not be mounted\n"), be_root_pool
);
1825 * Get the mountpoint for the root pool dataset.
1827 if (!zfs_is_mounted(zhp
, &rpool_mntpnt
)) {
1828 be_print_err(gettext("be_has_menu_entry: pool "
1829 "dataset (%s) is not mounted. Can't set "
1830 "the default BE in the grub menu.\n"), be_root_pool
);
1835 if (be_has_grub()) {
1836 (void) snprintf(menu_file
, MAXPATHLEN
, "/%s%s",
1837 rpool_mntpnt
, BE_GRUB_MENU
);
1839 (void) snprintf(menu_file
, MAXPATHLEN
, "/%s%s",
1840 rpool_mntpnt
, BE_SPARC_MENU
);
1843 if (be_open_menu(be_root_pool
, menu_file
, &menu_fp
, "r",
1847 } else if (menu_fp
== NULL
) {
1853 rpool_mntpnt
= NULL
;
1855 while (fgets(line
, BUFSIZ
, menu_fp
)) {
1856 char *tok
= strtok_r(line
, BE_WHITE_SPACE
, &last
);
1858 if (tok
!= NULL
&& tok
[0] != '#') {
1859 if (strcmp(tok
, "bootfs") == 0) {
1860 tok
= strtok_r(last
, BE_WHITE_SPACE
, &last
);
1861 if (tok
!= NULL
&& strcmp(tok
,
1863 (void) fclose(menu_fp
);
1865 * The entry number needs to be
1866 * decremented here because the title
1867 * will always be the first line for
1868 * an entry. Because of this we'll
1869 * always be off by one entry when we
1872 *entry
= ent_num
- 1;
1876 } else if (strcmp(tok
, "title") == 0)
1883 (void) be_unmount_pool(zhp
, ptmp_mntpnt
, orig_mntpnt
);
1888 (void) fclose(menu_fp
);
1893 * Function: be_update_vfstab
1894 * Description: This function digs into a BE's vfstab and updates all
1895 * entries with file systems listed in be_fs_list_data_t.
1896 * The entry's root container dataset and be_name will be
1897 * updated with the parameters passed in.
1899 * be_name - name of BE to update
1900 * old_rc_loc - dataset under which the root container dataset
1901 * of the old BE resides in.
1902 * new_rc_loc - dataset under which the root container dataset
1903 * of the new BE resides in.
1904 * fld - be_fs_list_data_t pointer providing the list of
1905 * file systems to look for in vfstab.
1906 * mountpoint - directory of where BE is currently mounted.
1907 * If NULL, then BE is not currently mounted.
1909 * BE_SUCCESS - Success
1910 * be_errno_t - Failure
1912 * Semi-private (library wide use only)
1915 be_update_vfstab(char *be_name
, char *old_rc_loc
, char *new_rc_loc
,
1916 be_fs_list_data_t
*fld
, char *mountpoint
)
1918 char *tmp_mountpoint
= NULL
;
1919 char alt_vfstab
[MAXPATHLEN
];
1920 int ret
= BE_SUCCESS
, err
= BE_SUCCESS
;
1922 if (fld
== NULL
|| fld
->fs_list
== NULL
|| fld
->fs_num
== 0)
1923 return (BE_SUCCESS
);
1925 /* If BE not already mounted, mount the BE */
1926 if (mountpoint
== NULL
) {
1927 if ((ret
= _be_mount(be_name
, &tmp_mountpoint
,
1928 BE_MOUNT_FLAG_NO_ZONES
)) != BE_SUCCESS
) {
1929 be_print_err(gettext("be_update_vfstab: "
1930 "failed to mount BE (%s)\n"), be_name
);
1934 tmp_mountpoint
= mountpoint
;
1937 /* Get string for vfstab in the mounted BE. */
1938 (void) snprintf(alt_vfstab
, sizeof (alt_vfstab
), "%s/etc/vfstab",
1941 /* Update the vfstab */
1942 ret
= _update_vfstab(alt_vfstab
, be_name
, old_rc_loc
, new_rc_loc
,
1945 /* Unmount BE if we mounted it */
1946 if (mountpoint
== NULL
) {
1947 if ((err
= _be_unmount(be_name
, 0)) == BE_SUCCESS
) {
1948 /* Remove temporary mountpoint */
1949 (void) rmdir(tmp_mountpoint
);
1951 be_print_err(gettext("be_update_vfstab: "
1952 "failed to unmount BE %s mounted at %s\n"),
1953 be_name
, tmp_mountpoint
);
1954 if (ret
== BE_SUCCESS
)
1958 free(tmp_mountpoint
);
1965 * Function: be_update_zone_vfstab
1966 * Description: This function digs into a zone BE's vfstab and updates all
1967 * entries with file systems listed in be_fs_list_data_t.
1968 * The entry's root container dataset and be_name will be
1969 * updated with the parameters passed in.
1971 * zhp - zfs_handle_t pointer to zone root dataset.
1972 * be_name - name of zone BE to update
1973 * old_rc_loc - dataset under which the root container dataset
1974 * of the old zone BE resides in.
1975 * new_rc_loc - dataset under which the root container dataset
1976 * of the new zone BE resides in.
1977 * fld - be_fs_list_data_t pointer providing the list of
1978 * file systems to look for in vfstab.
1980 * BE_SUCCESS - Success
1981 * be_errno_t - Failure
1983 * Semi-private (library wide use only)
1986 be_update_zone_vfstab(zfs_handle_t
*zhp
, char *be_name
, char *old_rc_loc
,
1987 char *new_rc_loc
, be_fs_list_data_t
*fld
)
1989 be_mount_data_t md
= { 0 };
1990 be_unmount_data_t ud
= { 0 };
1991 char alt_vfstab
[MAXPATHLEN
];
1992 boolean_t mounted_here
= B_FALSE
;
1993 int ret
= BE_SUCCESS
;
1996 * If zone root not already mounted, mount it at a
1997 * temporary location.
1999 if (!zfs_is_mounted(zhp
, &md
.altroot
)) {
2000 /* Generate temporary mountpoint to mount zone root */
2001 if ((ret
= be_make_tmp_mountpoint(&md
.altroot
)) != BE_SUCCESS
) {
2002 be_print_err(gettext("be_update_zone_vfstab: "
2003 "failed to make temporary mountpoint to "
2004 "mount zone root\n"));
2008 if (be_mount_zone_root(zhp
, &md
) != BE_SUCCESS
) {
2009 be_print_err(gettext("be_update_zone_vfstab: "
2010 "failed to mount zone root %s\n"),
2013 return (BE_ERR_MOUNT_ZONEROOT
);
2015 mounted_here
= B_TRUE
;
2018 /* Get string from vfstab in the mounted zone BE */
2019 (void) snprintf(alt_vfstab
, sizeof (alt_vfstab
), "%s/etc/vfstab",
2022 /* Update the vfstab */
2023 ret
= _update_vfstab(alt_vfstab
, be_name
, old_rc_loc
, new_rc_loc
,
2026 /* Unmount zone root if we mounted it */
2030 if (be_unmount_zone_root(zhp
, &ud
) == BE_SUCCESS
) {
2031 /* Remove the temporary mountpoint */
2032 (void) rmdir(md
.altroot
);
2034 be_print_err(gettext("be_update_zone_vfstab: "
2035 "failed to unmount zone root %s from %s\n"),
2036 zfs_get_name(zhp
), md
.altroot
);
2038 ret
= BE_ERR_UMOUNT_ZONEROOT
;
2047 * Function: be_auto_snap_name
2048 * Description: Generate an auto snapshot name constructed based on the
2049 * current date and time. The auto snapshot name is of the form:
2053 * where <date> is in ISO standard format, so the resultant name
2061 * Success - pointer to auto generated snapshot name. The name
2062 * is allocated in heap storage so the caller is
2063 * responsible for free'ing the name.
2066 * Semi-private (library wide use only)
2069 be_auto_snap_name(void)
2071 time_t utc_tm
= NULL
;
2072 struct tm
*gmt_tm
= NULL
;
2073 char gmt_time_str
[64];
2074 char *auto_snap_name
= NULL
;
2076 if (time(&utc_tm
) == -1) {
2077 be_print_err(gettext("be_auto_snap_name: time() failed\n"));
2081 if ((gmt_tm
= gmtime(&utc_tm
)) == NULL
) {
2082 be_print_err(gettext("be_auto_snap_name: gmtime() failed\n"));
2086 (void) strftime(gmt_time_str
, sizeof (gmt_time_str
), "%F-%T", gmt_tm
);
2088 if ((auto_snap_name
= strdup(gmt_time_str
)) == NULL
) {
2089 be_print_err(gettext("be_auto_snap_name: "
2090 "memory allocation failed\n"));
2094 return (auto_snap_name
);
2098 * Function: be_auto_be_name
2099 * Description: Generate an auto BE name constructed based on the BE name
2100 * of the original BE being cloned.
2102 * obe_name - name of the original BE being cloned.
2104 * Success - pointer to auto generated BE name. The name
2105 * is allocated in heap storage so the caller is
2106 * responsible for free'ing the name.
2109 * Semi-private (library wide use only)
2112 be_auto_be_name(char *obe_name
)
2114 return (be_get_auto_name(obe_name
, NULL
, B_FALSE
));
2118 * Function: be_auto_zone_be_name
2119 * Description: Generate an auto BE name for a zone constructed based on
2120 * the BE name of the original zone BE being cloned.
2122 * container_ds - container dataset for the zone.
2123 * zbe_name - name of the original zone BE being cloned.
2125 * Success - pointer to auto generated BE name. The name
2126 * is allocated in heap storage so the caller is
2127 * responsible for free'ing the name.
2130 * Semi-private (library wide use only)
2133 be_auto_zone_be_name(char *container_ds
, char *zbe_name
)
2135 return (be_get_auto_name(zbe_name
, container_ds
, B_TRUE
));
2139 * Function: be_valid_be_name
2140 * Description: Validates a BE name.
2142 * be_name - name of BE to validate
2144 * B_TRUE - be_name is valid
2145 * B_FALSE - be_name is invalid
2147 * Semi-private (library wide use only)
2151 be_valid_be_name(const char *be_name
)
2153 const char *c
= NULL
;
2154 struct be_defaults be_defaults
;
2156 if (be_name
== NULL
)
2159 be_get_defaults(&be_defaults
);
2162 * A BE name must not be a multi-level dataset name. We also check
2163 * that it does not contain the ' ' and '%' characters. The ' ' is
2164 * a valid character for datasets, however we don't allow that in a
2165 * BE name. The '%' is invalid, but zfs_name_valid() allows it for
2166 * internal reasons, so we explicitly check for it here.
2169 while (*c
!= '\0' && *c
!= '/' && *c
!= ' ' && *c
!= '%')
2176 * The BE name must comply with a zfs dataset filesystem. We also
2177 * verify its length to be < BE_NAME_MAX_LEN.
2179 if (!zfs_name_valid(be_name
, ZFS_TYPE_FILESYSTEM
) ||
2180 strlen(be_name
) > BE_NAME_MAX_LEN
)
2183 if (be_defaults
.be_deflt_bename_starts_with
[0] != '\0' &&
2184 strstr(be_name
, be_defaults
.be_deflt_bename_starts_with
) == NULL
) {
2192 * Function: be_valid_auto_snap_name
2193 * Description: This function checks that a snapshot name is a valid auto
2194 * generated snapshot name. A valid auto generated snapshot
2195 * name is of the form:
2199 * An older form of the auto generated snapshot name also
2200 * included the snapshot's BE cleanup policy and a reserved
2201 * field. Those names will also be verified by this function.
2203 * Examples of valid auto snapshot names are:
2205 * 2008-03-31-18:41:30
2206 * 2008-03-31-22:17:24
2207 * <policy>:-:2008:04-05-09:12:55
2208 * <policy>:-:2008:04-06-15:34:12
2211 * name - name of the snapshot to be validated.
2213 * B_TRUE - the name is a valid auto snapshot name.
2214 * B_FALSE - the name is not a valid auto snapshot name.
2216 * Semi-private (library wide use only)
2219 be_valid_auto_snap_name(char *name
)
2223 char *policy
= NULL
;
2224 char *reserved
= NULL
;
2228 /* Validate the snapshot name by converting it into utc time */
2229 if (strptime(name
, "%Y-%m-%d-%T", &gmt_tm
) != NULL
&&
2230 (mktime(&gmt_tm
) != -1)) {
2235 * Validate the snapshot name against the older form of an
2236 * auto generated snapshot name.
2238 policy
= strdup(name
);
2241 * Get the first field from the snapshot name,
2242 * which is the BE policy
2244 c
= strchr(policy
, ':');
2251 /* Validate the policy name */
2252 if (!valid_be_policy(policy
)) {
2257 /* Get the next field, which is the reserved field. */
2258 if (c
[1] == NULL
|| c
[1] == '\0') {
2263 c
= strchr(reserved
, ':');
2270 /* Validate the reserved field */
2271 if (strcmp(reserved
, "-") != 0) {
2276 /* The remaining string should be the date field */
2277 if (c
[1] == NULL
|| c
[1] == '\0') {
2283 /* Validate the date string by converting it into utc time */
2284 if (strptime(date
, "%Y-%m-%d-%T", &gmt_tm
) == NULL
||
2285 (mktime(&gmt_tm
) == -1)) {
2286 be_print_err(gettext("be_valid_auto_snap_name: "
2287 "invalid auto snapshot name\n"));
2297 * Function: be_default_policy
2298 * Description: Temporary hardcoded policy support. This function returns
2299 * the default policy type to be used to create a BE or a BE
2304 * Name of default BE policy.
2306 * Semi-private (library wide use only)
2309 be_default_policy(void)
2311 return (BE_PLCY_STATIC
);
2315 * Function: valid_be_policy
2316 * Description: Temporary hardcoded policy support. This function valids
2317 * whether a policy is a valid known policy or not.
2319 * policy - name of policy to validate.
2321 * B_TRUE - policy is a valid.
2322 * B_FALSE - policy is invalid.
2324 * Semi-private (library wide use only)
2327 valid_be_policy(char *policy
)
2332 if (strcmp(policy
, BE_PLCY_STATIC
) == 0 ||
2333 strcmp(policy
, BE_PLCY_VOLATILE
) == 0) {
2341 * Function: be_print_err
2342 * Description: This function prints out error messages if do_print is
2343 * set to B_TRUE or if the BE_PRINT_ERR environment variable
2346 * prnt_str - the string we wish to print and any arguments
2347 * for the format of that string.
2351 * Semi-private (library wide use only)
2354 be_print_err(char *prnt_str
, ...)
2359 static boolean_t env_checked
= B_FALSE
;
2362 if ((env_buf
= getenv("BE_PRINT_ERR")) != NULL
) {
2363 if (strcasecmp(env_buf
, "true") == 0) {
2367 env_checked
= B_TRUE
;
2371 va_start(ap
, prnt_str
);
2372 /* LINTED variable format specifier */
2373 (void) vsnprintf(buf
, BUFSIZ
, prnt_str
, ap
);
2374 (void) fputs(buf
, stderr
);
2380 * Function: be_find_current_be
2381 * Description: Find the currently "active" BE. Fill in the
2382 * passed in be_transaction_data_t reference with the
2387 * BE_SUCCESS - Success
2388 * be_errnot_t - Failure
2390 * Semi-private (library wide use only)
2392 * The caller is responsible for initializing the libzfs handle
2393 * and freeing the memory used by the active be_name.
2396 be_find_current_be(be_transaction_data_t
*bt
)
2400 if ((zret
= zpool_iter(g_zfs
, be_zpool_find_current_be_callback
,
2402 be_print_err(gettext("be_find_current_be: failed to "
2403 "find current BE name\n"));
2404 return (BE_ERR_BE_NOENT
);
2405 } else if (zret
< 0) {
2406 be_print_err(gettext("be_find_current_be: "
2407 "zpool_iter failed: %s\n"),
2408 libzfs_error_description(g_zfs
));
2409 return (zfs_err_to_be_err(g_zfs
));
2412 return (BE_SUCCESS
);
2416 * Function: be_zpool_find_current_be_callback
2417 * Description: Callback function used to iterate through all existing pools
2418 * to find the BE that is the currently booted BE.
2420 * zlp - zpool_handle_t pointer to the current pool being
2422 * data - be_transaction_data_t pointer.
2423 * Upon successfully finding the current BE, the
2424 * obe_zpool member of this parameter is set to the
2425 * pool it is found in.
2427 * 1 - Found current BE in this pool.
2428 * 0 - Did not find current BE in this pool.
2430 * Semi-private (library wide use only)
2433 be_zpool_find_current_be_callback(zpool_handle_t
*zlp
, void *data
)
2435 be_transaction_data_t
*bt
= data
;
2436 zfs_handle_t
*zhp
= NULL
;
2437 const char *zpool
= zpool_get_name(zlp
);
2438 char be_container_ds
[MAXPATHLEN
];
2441 * Generate string for BE container dataset
2443 be_make_container_ds(zpool
, be_container_ds
, sizeof (be_container_ds
));
2446 * Check if a BE container dataset exists in this pool.
2448 if (!zfs_dataset_exists(g_zfs
, be_container_ds
, ZFS_TYPE_FILESYSTEM
)) {
2454 * Get handle to this zpool's BE container dataset.
2456 if ((zhp
= zfs_open(g_zfs
, be_container_ds
, ZFS_TYPE_FILESYSTEM
)) ==
2458 be_print_err(gettext("be_zpool_find_current_be_callback: "
2459 "failed to open BE container dataset (%s)\n"),
2466 * Iterate through all potential BEs in this zpool
2468 if (zfs_iter_filesystems(zhp
, be_zfs_find_current_be_callback
, bt
)) {
2470 * Found current BE dataset; set obe_zpool
2472 if ((bt
->obe_zpool
= strdup(zpool
)) == NULL
) {
2473 be_print_err(gettext(
2474 "be_zpool_find_current_be_callback: "
2475 "memory allocation failed\n"));
2493 * Function: be_zfs_find_current_be_callback
2494 * Description: Callback function used to iterate through all BEs in a
2495 * pool to find the BE that is the currently booted BE.
2497 * zhp - zfs_handle_t pointer to current filesystem being checked.
2498 * data - be_transaction-data_t pointer
2499 * Upon successfully finding the current BE, the
2500 * obe_name and obe_root_ds members of this parameter
2501 * are set to the BE name and BE's root dataset
2504 * 1 - Found current BE.
2505 * 0 - Did not find current BE.
2507 * Semi-private (library wide use only)
2510 be_zfs_find_current_be_callback(zfs_handle_t
*zhp
, void *data
)
2512 be_transaction_data_t
*bt
= data
;
2516 * Check if dataset is mounted, and if so where.
2518 if (zfs_is_mounted(zhp
, &mp
)) {
2520 * If mounted at root, set obe_root_ds and obe_name
2522 if (mp
!= NULL
&& strcmp(mp
, "/") == 0) {
2525 if ((bt
->obe_root_ds
= strdup(zfs_get_name(zhp
)))
2527 be_print_err(gettext(
2528 "be_zfs_find_current_be_callback: "
2529 "memory allocation failed\n"));
2534 if ((bt
->obe_name
= strdup(basename(bt
->obe_root_ds
)))
2536 be_print_err(gettext(
2537 "be_zfs_find_current_be_callback: "
2538 "memory allocation failed\n"));
2555 * Function: be_check_be_roots_callback
2556 * Description: This function checks whether or not the dataset name passed
2557 * is hierachically located under the BE root container dataset
2560 * zlp - zpool_handle_t pointer to current pool being processed.
2561 * data - name of dataset to check
2563 * 0 - dataset is not in this pool's BE root container dataset
2564 * 1 - dataset is in this pool's BE root container dataset
2566 * Semi-private (library wide use only)
2569 be_check_be_roots_callback(zpool_handle_t
*zlp
, void *data
)
2571 const char *zpool
= zpool_get_name(zlp
);
2573 char be_container_ds
[MAXPATHLEN
];
2575 /* Generate string for this pool's BE root container dataset */
2576 be_make_container_ds(zpool
, be_container_ds
, sizeof (be_container_ds
));
2579 * If dataset lives under the BE root container dataset
2580 * of this pool, return failure.
2582 if (strncmp(be_container_ds
, ds
, strlen(be_container_ds
)) == 0 &&
2583 ds
[strlen(be_container_ds
)] == '/') {
2593 * Function: zfs_err_to_be_err
2594 * Description: This function takes the error stored in the libzfs handle
2595 * and maps it to an be_errno_t. If there are no matching
2596 * be_errno_t's then BE_ERR_ZFS is returned.
2598 * zfsh - The libzfs handle containing the error we're looking up.
2602 * Semi-private (library wide use only)
2605 zfs_err_to_be_err(libzfs_handle_t
*zfsh
)
2607 int err
= libzfs_errno(zfsh
);
2611 return (BE_SUCCESS
);
2613 return (BE_ERR_PERM
);
2615 return (BE_ERR_INTR
);
2617 return (BE_ERR_NOENT
);
2619 return (BE_ERR_NOSPC
);
2620 case EZFS_MOUNTFAILED
:
2621 return (BE_ERR_MOUNT
);
2622 case EZFS_UMOUNTFAILED
:
2623 return (BE_ERR_UMOUNT
);
2625 return (BE_ERR_BE_EXISTS
);
2627 return (BE_ERR_DEV_BUSY
);
2628 case EZFS_POOLREADONLY
:
2629 return (BE_ERR_ROFS
);
2630 case EZFS_NAMETOOLONG
:
2631 return (BE_ERR_NAMETOOLONG
);
2633 return (BE_ERR_NODEV
);
2634 case EZFS_POOL_INVALARG
:
2635 return (BE_ERR_INVAL
);
2637 return (BE_ERR_INVALPROP
);
2639 return (BE_ERR_DSTYPE
);
2640 case EZFS_PROPNONINHERIT
:
2641 return (BE_ERR_NONINHERIT
);
2642 case EZFS_PROPREADONLY
:
2643 return (BE_ERR_READONLYPROP
);
2644 case EZFS_RESILVERING
:
2645 case EZFS_POOLUNAVAIL
:
2646 return (BE_ERR_UNAVAIL
);
2647 case EZFS_DSREADONLY
:
2648 return (BE_ERR_READONLYDS
);
2650 return (BE_ERR_ZFS
);
2655 * Function: errno_to_be_err
2656 * Description: This function takes an errno and maps it to an be_errno_t.
2657 * If there are no matching be_errno_t's then BE_ERR_UNKNOWN is
2660 * err - The errno we're compairing against.
2664 * Semi-private (library wide use only)
2667 errno_to_be_err(int err
)
2671 return (BE_ERR_PERM
);
2673 return (BE_ERR_ACCESS
);
2675 return (BE_ERR_CANCELED
);
2677 return (BE_ERR_INTR
);
2679 return (BE_ERR_NOENT
);
2682 return (BE_ERR_NOSPC
);
2684 return (BE_ERR_BE_EXISTS
);
2686 return (BE_ERR_BUSY
);
2688 return (BE_ERR_ROFS
);
2690 return (BE_ERR_NAMETOOLONG
);
2692 return (BE_ERR_NXIO
);
2694 return (BE_ERR_INVAL
);
2696 return (BE_ERR_FAULT
);
2698 return (BE_ERR_UNKNOWN
);
2703 * Function: be_err_to_str
2704 * Description: This function takes a be_errno_t and maps it to a message.
2705 * If there are no matching be_errno_t's then NULL is returned.
2707 * be_errno_t - The be_errno_t we're mapping.
2709 * string or NULL if the error code is not known.
2711 * Semi-private (library wide use only)
2714 be_err_to_str(int err
)
2718 return (gettext("Permission denied."));
2719 case BE_ERR_ACTIVATE_CURR
:
2720 return (gettext("Activation of current BE failed."));
2721 case BE_ERR_AUTONAME
:
2722 return (gettext("Auto naming failed."));
2723 case BE_ERR_BE_NOENT
:
2724 return (gettext("No such BE."));
2726 return (gettext("Mount busy."));
2727 case BE_ERR_DEV_BUSY
:
2728 return (gettext("Device busy."));
2729 case BE_ERR_CANCELED
:
2730 return (gettext("Operation canceled."));
2732 return (gettext("BE clone failed."));
2734 return (gettext("BE copy failed."));
2735 case BE_ERR_CREATDS
:
2736 return (gettext("Dataset creation failed."));
2737 case BE_ERR_CURR_BE_NOT_FOUND
:
2738 return (gettext("Can't find current BE."));
2739 case BE_ERR_DESTROY
:
2740 return (gettext("Failed to destroy BE or snapshot."));
2741 case BE_ERR_DESTROY_CURR_BE
:
2742 return (gettext("Cannot destroy current BE."));
2744 return (gettext("BE demotion failed."));
2746 return (gettext("Invalid dataset type."));
2747 case BE_ERR_BE_EXISTS
:
2748 return (gettext("BE exists."));
2750 return (gettext("be_zfs_init failed."));
2752 return (gettext("Interupted system call."));
2754 return (gettext("Invalid argument."));
2755 case BE_ERR_INVALPROP
:
2756 return (gettext("Invalid property for dataset."));
2757 case BE_ERR_INVALMOUNTPOINT
:
2758 return (gettext("Unexpected mountpoint."));
2760 return (gettext("Mount failed."));
2761 case BE_ERR_MOUNTED
:
2762 return (gettext("Already mounted."));
2763 case BE_ERR_NAMETOOLONG
:
2764 return (gettext("name > BUFSIZ."));
2766 return (gettext("Doesn't exist."));
2767 case BE_ERR_POOL_NOENT
:
2768 return (gettext("No such pool."));
2770 return (gettext("No such device."));
2771 case BE_ERR_NOTMOUNTED
:
2772 return (gettext("File system not mounted."));
2774 return (gettext("Not enough memory."));
2775 case BE_ERR_NONINHERIT
:
2777 "Property is not inheritable for the BE dataset."));
2779 return (gettext("No such device or address."));
2781 return (gettext("No space on device."));
2783 return (gettext("Operation not supported."));
2785 return (gettext("Open failed."));
2787 return (gettext("Not owner."));
2788 case BE_ERR_UNAVAIL
:
2789 return (gettext("The BE is currently unavailable."));
2790 case BE_ERR_PROMOTE
:
2791 return (gettext("BE promotion failed."));
2793 return (gettext("Read only file system."));
2794 case BE_ERR_READONLYDS
:
2795 return (gettext("Read only dataset."));
2796 case BE_ERR_READONLYPROP
:
2797 return (gettext("Read only property."));
2798 case BE_ERR_RENAME_ACTIVE
:
2799 return (gettext("Renaming the active BE is not supported."));
2800 case BE_ERR_SS_EXISTS
:
2801 return (gettext("Snapshot exists."));
2802 case BE_ERR_SS_NOENT
:
2803 return (gettext("No such snapshot."));
2805 return (gettext("Unmount failed."));
2806 case BE_ERR_UMOUNT_CURR_BE
:
2807 return (gettext("Can't unmount the current BE."));
2808 case BE_ERR_UMOUNT_SHARED
:
2809 return (gettext("Unmount of a shared File System failed."));
2811 return (gettext("Bad address."));
2812 case BE_ERR_UNKNOWN
:
2813 return (gettext("Unknown error."));
2815 return (gettext("ZFS returned an error."));
2816 case BE_ERR_GEN_UUID
:
2817 return (gettext("Failed to generate uuid."));
2818 case BE_ERR_PARSE_UUID
:
2819 return (gettext("Failed to parse uuid."));
2820 case BE_ERR_NO_UUID
:
2821 return (gettext("No uuid"));
2822 case BE_ERR_ZONE_NO_PARENTBE
:
2823 return (gettext("No parent uuid"));
2824 case BE_ERR_ZONE_MULTIPLE_ACTIVE
:
2825 return (gettext("Multiple active zone roots"));
2826 case BE_ERR_ZONE_NO_ACTIVE_ROOT
:
2827 return (gettext("No active zone root"));
2828 case BE_ERR_ZONE_ROOT_NOT_LEGACY
:
2829 return (gettext("Zone root not legacy"));
2830 case BE_ERR_MOUNT_ZONEROOT
:
2831 return (gettext("Failed to mount a zone root."));
2832 case BE_ERR_UMOUNT_ZONEROOT
:
2833 return (gettext("Failed to unmount a zone root."));
2834 case BE_ERR_NO_MOUNTED_ZONE
:
2835 return (gettext("Zone is not mounted"));
2836 case BE_ERR_ZONES_UNMOUNT
:
2837 return (gettext("Unable to unmount a zone BE."));
2838 case BE_ERR_NO_MENU
:
2839 return (gettext("Missing boot menu file."));
2840 case BE_ERR_BAD_MENU_PATH
:
2841 return (gettext("Invalid path for menu.lst file"));
2842 case BE_ERR_ZONE_SS_EXISTS
:
2843 return (gettext("Zone snapshot exists."));
2844 case BE_ERR_BOOTFILE_INST
:
2845 return (gettext("Error installing boot files."));
2847 return (gettext("Error running an external command."));
2854 * Function: be_has_grub
2855 * Description: Boolean function indicating whether the current system
2857 * Return: B_FALSE - the system does not have grub
2858 * B_TRUE - the system does have grub.
2860 * Semi-private (library wide use only)
2866 * TODO: This will need to be expanded to check for the existence of
2867 * grub if and when there is grub support for SPARC.
2869 return (be_is_isa("i386"));
2873 * Function: be_is_isa
2874 * Description: Boolean function indicating whether the instruction set
2875 * architecture of the executing system matches the name provided.
2876 * The string must match a system defined architecture (e.g.
2877 * "i386", "sparc") and is case sensitive.
2878 * Parameters: name - string representing the name of instruction set
2879 * architecture being tested
2880 * Returns: B_FALSE - the system instruction set architecture is different
2881 * from the one specified
2882 * B_TRUE - the system instruction set architecture is the same
2883 * as the one specified
2885 * Semi-private (library wide use only)
2888 be_is_isa(char *name
)
2890 return ((strcmp((char *)be_get_default_isa(), name
) == 0));
2894 * Function: be_get_default_isa
2896 * Returns the default instruction set architecture of the
2897 * machine it is executed on. (eg. sparc, i386, ...)
2898 * NOTE: SYS_INST environment variable may override default
2903 * NULL - the architecture returned by sysinfo() was too
2904 * long for local variables
2905 * char * - pointer to a string containing the default
2908 * Semi-private (library wide use only)
2911 be_get_default_isa(void)
2915 static char default_inst
[ARCH_LENGTH
] = "";
2917 if (default_inst
[0] == '\0') {
2918 if ((envp
= getenv("SYS_INST")) != NULL
) {
2919 if ((int)strlen(envp
) >= ARCH_LENGTH
)
2922 (void) strcpy(default_inst
, envp
);
2924 i
= sysinfo(SI_ARCHITECTURE
, default_inst
, ARCH_LENGTH
);
2925 if (i
< 0 || i
> ARCH_LENGTH
)
2929 return (default_inst
);
2933 * Function: be_run_cmd
2935 * Runs a command in a separate subprocess. Splits out stdout from stderr
2936 * and sends each to its own buffer. Buffers must be pre-allocated and
2937 * passed in as arguments. Buffer sizes are also passed in as arguments.
2940 * - Command being run is assumed to not have any stdout or stderr
2942 * - Commands which emit total stderr output of greater than PIPE_BUF
2943 * bytes can hang. For such commands, a different implementation
2944 * which uses poll(2) must be used.
2945 * - stdout_buf can be NULL. In this case, stdout_bufsize is ignored, and
2946 * the stream which would have gone to it is sent to the bit
2948 * - stderr_buf cannot be NULL.
2949 * - Only subprocess errors are appended to the stderr_buf. Errors
2950 * running the command are reported through be_print_err().
2951 * - Data which would overflow its respective buffer is sent to the bit
2955 * command: command to run. Assumed not to have embedded stdout
2956 * or stderr redirection. May have stdin redirection,
2958 * stderr_buf: buffer returning subprocess stderr data. Errors
2959 * reported by this function are reported through
2961 * stderr_bufsize: size of stderr_buf
2962 * stdout_buf: buffer returning subprocess stdout data.
2963 * stdout_bufsize: size of stdout_buf
2965 * BE_SUCCESS - The command ran successfully without returning
2968 * - The command could not be run.
2969 * - The command terminated with error status.
2970 * - There were errors extracting or returning subprocess
2972 * BE_ERR_NOMEM - The command exceeds the command buffer size.
2973 * BE_ERR_INVAL - An invalid argument was specified.
2975 * Semi-private (library wide use only)
2978 be_run_cmd(char *command
, char *stderr_buf
, int stderr_bufsize
,
2979 char *stdout_buf
, int stdout_bufsize
)
2981 char *temp_filename
= strdup(tmpnam(NULL
));
2982 FILE *stdout_str
= NULL
;
2983 FILE *stderr_str
= NULL
;
2984 char cmdline
[BUFSIZ
];
2985 char oneline
[BUFSIZ
];
2987 int rval
= BE_SUCCESS
;
2989 if ((command
== NULL
) || (stderr_buf
== NULL
) ||
2990 (stderr_bufsize
<= 0) || (stdout_bufsize
< 0) ||
2991 ((stdout_buf
!= NULL
) ^ (stdout_bufsize
!= 0))) {
2992 return (BE_ERR_INVAL
);
2995 /* Set up command so popen returns stderr, not stdout */
2996 if (snprintf(cmdline
, BUFSIZ
, "%s 2> %s", command
,
2997 temp_filename
) >= BUFSIZ
) {
2998 rval
= BE_ERR_NOMEM
;
3002 /* Set up the fifo that will make stderr available. */
3003 if (mkfifo(temp_filename
, 0600) != 0) {
3004 (void) be_print_err(gettext("be_run_cmd: mkfifo: %s\n"),
3006 rval
= BE_ERR_EXTCMD
;
3010 if ((stdout_str
= popen(cmdline
, "r")) == NULL
) {
3011 (void) be_print_err(gettext("be_run_cmd: popen: %s\n"),
3013 rval
= BE_ERR_EXTCMD
;
3017 if ((stderr_str
= fopen(temp_filename
, "r")) == NULL
) {
3018 (void) be_print_err(gettext("be_run_cmd: fopen: %s\n"),
3020 (void) pclose(stdout_str
);
3021 rval
= BE_ERR_EXTCMD
;
3025 /* Read stdout first, as it usually outputs more than stderr. */
3026 oneline
[BUFSIZ
-1] = '\0';
3027 while (fgets(oneline
, BUFSIZ
-1, stdout_str
) != NULL
) {
3028 if (stdout_str
!= NULL
) {
3029 (void) strlcat(stdout_buf
, oneline
, stdout_bufsize
);
3033 while (fgets(oneline
, BUFSIZ
-1, stderr_str
) != NULL
) {
3034 (void) strlcat(stderr_buf
, oneline
, stderr_bufsize
);
3037 /* Close pipe, get exit status. */
3038 if ((exit_status
= pclose(stdout_str
)) == -1) {
3039 (void) be_print_err(gettext("be_run_cmd: pclose: %s\n"),
3041 rval
= BE_ERR_EXTCMD
;
3042 } else if (WIFEXITED(exit_status
)) {
3043 exit_status
= (int)((char)WEXITSTATUS(exit_status
));
3044 if (exit_status
!= 0) {
3045 (void) snprintf(oneline
, BUFSIZ
, gettext("be_run_cmd: "
3046 "command terminated with error status: %d\n"),
3048 (void) strlcat(stderr_buf
, oneline
, stderr_bufsize
);
3049 rval
= BE_ERR_EXTCMD
;
3052 (void) snprintf(oneline
, BUFSIZ
, gettext("be_run_cmd: command "
3053 "terminated on signal: %s\n"),
3054 strsignal(WTERMSIG(exit_status
)));
3055 (void) strlcat(stderr_buf
, oneline
, stderr_bufsize
);
3056 rval
= BE_ERR_EXTCMD
;
3060 (void) unlink(temp_filename
);
3061 (void) free(temp_filename
);
3066 /* ******************************************************************** */
3067 /* Private Functions */
3068 /* ******************************************************************** */
3071 * Function: update_dataset
3072 * Description: This function takes a dataset name and replaces the zpool
3073 * and be_name components of the dataset with the new be_name
3076 * dataset - name of dataset
3077 * dataset_len - lenth of buffer in which dataset is passed in.
3078 * be_name - name of new BE name to update to.
3079 * old_rc_loc - dataset under which the root container dataset
3080 * for the old BE lives.
3081 * new_rc_loc - dataset under which the root container dataset
3082 * for the new BE lives.
3084 * BE_SUCCESS - Success
3085 * be_errno_t - Failure
3090 update_dataset(char *dataset
, int dataset_len
, char *be_name
,
3091 char *old_rc_loc
, char *new_rc_loc
)
3094 char *sub_ds
= NULL
;
3096 /* Tear off the BE container dataset */
3097 if ((ds
= be_make_name_from_ds(dataset
, old_rc_loc
)) == NULL
) {
3098 return (BE_ERR_INVAL
);
3101 /* Get dataset name relative to BE root, if there is one */
3102 sub_ds
= strchr(ds
, '/');
3104 /* Generate the BE root dataset name */
3105 be_make_root_ds(new_rc_loc
, be_name
, dataset
, dataset_len
);
3107 /* If a subordinate dataset name was found, append it */
3109 (void) strlcat(dataset
, sub_ds
, dataset_len
);
3112 return (BE_SUCCESS
);
3116 * Function: _update_vfstab
3117 * Description: This function updates a vfstab file to reflect the new
3118 * root container dataset location and be_name for all
3119 * entries listed in the be_fs_list_data_t structure passed in.
3121 * vfstab - vfstab file to modify
3122 * be_name - name of BE to update.
3123 * old_rc_loc - dataset under which the root container dataset
3124 * of the old BE resides in.
3125 * new_rc_loc - dataset under which the root container dataset
3126 * of the new BE resides in.
3127 * fld - be_fs_list_data_t pointer providing the list of
3128 * file systems to look for in vfstab.
3130 * BE_SUCCESS - Success
3131 * be_errno_t - Failure
3136 _update_vfstab(char *vfstab
, char *be_name
, char *old_rc_loc
,
3137 char *new_rc_loc
, be_fs_list_data_t
*fld
)
3140 char *tmp_vfstab
= NULL
;
3141 char comments_buf
[BUFSIZ
];
3142 FILE *comments
= NULL
;
3143 FILE *vfs_ents
= NULL
;
3146 char dev
[MAXPATHLEN
];
3149 int ret
= BE_SUCCESS
, err
= 0;
3151 int tmp_vfstab_len
= 0;
3156 * Open vfstab for reading twice. First is for comments,
3157 * second is for actual entries.
3159 if ((comments
= fopen(vfstab
, "r")) == NULL
||
3160 (vfs_ents
= fopen(vfstab
, "r")) == NULL
) {
3162 be_print_err(gettext("_update_vfstab: "
3163 "failed to open vfstab (%s): %s\n"), vfstab
,
3165 ret
= errno_to_be_err(err
);
3169 /* Grab the stats of the original vfstab file */
3170 if (stat(vfstab
, &sb
) != 0) {
3172 be_print_err(gettext("_update_vfstab: "
3173 "failed to stat file %s: %s\n"), vfstab
,
3175 ret
= errno_to_be_err(err
);
3179 /* Create tmp file for modified vfstab */
3180 if ((tmp_vfstab
= (char *)malloc(strlen(vfstab
) + 7))
3182 be_print_err(gettext("_update_vfstab: "
3183 "malloc failed\n"));
3187 tmp_vfstab_len
= strlen(vfstab
) + 7;
3188 (void) memset(tmp_vfstab
, 0, tmp_vfstab_len
);
3189 (void) strlcpy(tmp_vfstab
, vfstab
, tmp_vfstab_len
);
3190 (void) strlcat(tmp_vfstab
, "XXXXXX", tmp_vfstab_len
);
3191 if ((fd
= mkstemp(tmp_vfstab
)) == -1) {
3193 be_print_err(gettext("_update_vfstab: "
3194 "mkstemp failed: %s\n"), strerror(err
));
3195 ret
= errno_to_be_err(err
);
3198 if ((tfile
= fdopen(fd
, "w")) == NULL
) {
3200 be_print_err(gettext("_update_vfstab: "
3201 "could not open file for write\n"));
3203 ret
= errno_to_be_err(err
);
3207 while (fgets(comments_buf
, BUFSIZ
, comments
)) {
3208 for (c
= comments_buf
; *c
!= '\0' && isspace(*c
); c
++)
3212 } else if (*c
== '#') {
3214 * If line is a comment line, just put
3215 * it through to the tmp vfstab.
3217 (void) fputs(comments_buf
, tfile
);
3220 * Else line is a vfstab entry, grab it
3221 * into a vfstab struct.
3223 if (getvfsent(vfs_ents
, &vp
) != 0) {
3225 be_print_err(gettext("_update_vfstab: "
3226 "getvfsent failed: %s\n"), strerror(err
));
3227 ret
= errno_to_be_err(err
);
3231 if (vp
.vfs_special
== NULL
|| vp
.vfs_mountp
== NULL
) {
3232 (void) putvfsent(tfile
, &vp
);
3237 * If the entry is one of the entries in the list
3238 * of file systems to update, modify it's device
3239 * field to be correct for this BE.
3241 for (i
= 0; i
< fld
->fs_num
; i
++) {
3242 if (strcmp(vp
.vfs_special
, fld
->fs_list
[i
])
3245 * Found entry that needs an update.
3246 * Replace the root container dataset
3247 * location and be_name in the
3250 (void) strlcpy(dev
, vp
.vfs_special
,
3253 if ((ret
= update_dataset(dev
,
3254 sizeof (dev
), be_name
, old_rc_loc
,
3255 new_rc_loc
)) != 0) {
3257 gettext("_update_vfstab: "
3258 "Failed to update device "
3259 "field for vfstab entry "
3260 "%s\n"), fld
->fs_list
[i
]);
3264 vp
.vfs_special
= dev
;
3269 /* Put entry through to tmp vfstab */
3270 (void) putvfsent(tfile
, &vp
);
3274 (void) fclose(comments
);
3276 (void) fclose(vfs_ents
);
3278 (void) fclose(tfile
);
3281 /* Copy tmp vfstab into place */
3282 if (rename(tmp_vfstab
, vfstab
) != 0) {
3284 be_print_err(gettext("_update_vfstab: "
3285 "failed to rename file %s to %s: %s\n"), tmp_vfstab
,
3286 vfstab
, strerror(err
));
3287 ret
= errno_to_be_err(err
);
3291 /* Set the perms and ownership of the updated file */
3292 if (chmod(vfstab
, sb
.st_mode
) != 0) {
3294 be_print_err(gettext("_update_vfstab: "
3295 "failed to chmod %s: %s\n"), vfstab
, strerror(err
));
3296 ret
= errno_to_be_err(err
);
3299 if (chown(vfstab
, sb
.st_uid
, sb
.st_gid
) != 0) {
3301 be_print_err(gettext("_update_vfstab: "
3302 "failed to chown %s: %s\n"), vfstab
, strerror(err
));
3303 ret
= errno_to_be_err(err
);
3308 if (comments
!= NULL
)
3309 (void) fclose(comments
);
3310 if (vfs_ents
!= NULL
)
3311 (void) fclose(vfs_ents
);
3312 (void) unlink(tmp_vfstab
);
3313 (void) free(tmp_vfstab
);
3315 (void) fclose(tfile
);
3322 * Function: be_get_auto_name
3323 * Description: Generate an auto name constructed based on the BE name
3324 * of the original BE or zone BE being cloned.
3326 * obe_name - name of the original BE or zone BE being cloned.
3327 * container_ds - container dataset for the zone.
3328 * Note: if zone_be is false this should be
3330 * zone_be - flag that indicates if we are operating on a zone BE.
3332 * Success - pointer to auto generated BE name. The name
3333 * is allocated in heap storage so the caller is
3334 * responsible for free'ing the name.
3340 be_get_auto_name(char *obe_name
, char *be_container_ds
, boolean_t zone_be
)
3342 be_node_list_t
*be_nodes
= NULL
;
3343 be_node_list_t
*cur_be
= NULL
;
3344 char auto_be_name
[MAXPATHLEN
];
3345 char base_be_name
[MAXPATHLEN
];
3346 char cur_be_name
[MAXPATHLEN
];
3347 char *num_str
= NULL
;
3355 * Check if obe_name is already in an auto BE name format.
3356 * If it is, then strip off the increment number to get the
3359 (void) strlcpy(base_be_name
, obe_name
, sizeof (base_be_name
));
3361 if ((num_str
= strrchr(base_be_name
, BE_AUTO_NAME_DELIM
))
3363 /* Make sure remaining string is all digits */
3365 while (c
[0] != '\0' && isdigit(c
[0]))
3368 * If we're now at the end of the string strip off the
3376 if (be_container_ds
== NULL
)
3378 if (be_get_zone_be_list(obe_name
, be_container_ds
,
3379 &be_nodes
) != BE_SUCCESS
) {
3380 be_print_err(gettext("be_get_auto_name: "
3381 "be_get_zone_be_list failed\n"));
3384 } else if (_be_list(NULL
, &be_nodes
) != BE_SUCCESS
) {
3385 be_print_err(gettext("be_get_auto_name: be_list failed\n"));
3389 for (cur_be
= be_nodes
; cur_be
!= NULL
; cur_be
= cur_be
->be_next_node
) {
3390 (void) strlcpy(cur_be_name
, cur_be
->be_node_name
,
3391 sizeof (cur_be_name
));
3393 /* If cur_be_name doesn't match at least base be name, skip. */
3394 if (strncmp(cur_be_name
, base_be_name
, strlen(base_be_name
))
3398 /* Get the string following the base be name */
3399 num_str
= cur_be_name
+ strlen(base_be_name
);
3402 * If nothing follows the base be name, this cur_be_name
3403 * is the BE named with the base be name, skip.
3405 if (num_str
== NULL
|| num_str
[0] == '\0')
3409 * Remove the name delimiter. If its not there,
3410 * cur_be_name isn't part of this BE name stream, skip.
3412 if (num_str
[0] == BE_AUTO_NAME_DELIM
)
3417 /* Make sure remaining string is all digits */
3419 while (c
[0] != '\0' && isdigit(c
[0]))
3424 /* Convert the number string to an int */
3425 cur_num
= atoi(num_str
);
3428 * If failed to convert the string, skip it. If its too
3429 * long to be converted to an int, we wouldn't auto generate
3430 * this number anyway so there couldn't be a conflict.
3431 * We treat it as a manually created BE name.
3433 if (cur_num
== 0 && errno
== EINVAL
)
3437 * Compare current number to current max number,
3438 * take higher of the two.
3445 * Store off a copy of 'num' incase we need it later. If incrementing
3446 * 'num' causes it to roll over, this means 'num' is the largest
3447 * positive int possible; we'll need it later in the loop to determine
3448 * if we've exhausted all possible increment numbers. We store it in
3453 /* Increment 'num' to get new auto BE name number */
3458 * Since incrementing 'num' caused it to rollover, start
3459 * over at 0 and find the first available number.
3461 for (num
= 0; num
< cur_num
; num
++) {
3463 (void) snprintf(cur_be_name
, sizeof (cur_be_name
),
3464 "%s%c%d", base_be_name
, BE_AUTO_NAME_DELIM
, num
);
3466 ret
= zpool_iter(g_zfs
, be_exists_callback
,
3471 * BE name doesn't exist, break out
3475 } else if (ret
== 1) {
3476 /* BE name exists, continue looking */
3479 be_print_err(gettext("be_get_auto_name: "
3480 "zpool_iter failed: %s\n"),
3481 libzfs_error_description(g_zfs
));
3482 be_free_list(be_nodes
);
3488 * If 'num' equals 'cur_num', we've exhausted all possible
3489 * auto BE names for this base BE name.
3491 if (num
== cur_num
) {
3492 be_print_err(gettext("be_get_auto_name: "
3493 "No more available auto BE names for base "
3494 "BE name %s\n"), base_be_name
);
3495 be_free_list(be_nodes
);
3500 be_free_list(be_nodes
);
3503 * Generate string for auto BE name.
3505 (void) snprintf(auto_be_name
, sizeof (auto_be_name
), "%s%c%d",
3506 base_be_name
, BE_AUTO_NAME_DELIM
, num
);
3508 if ((c
= strdup(auto_be_name
)) == NULL
) {
3509 be_print_err(gettext("be_get_auto_name: "
3510 "memory allocation failed\n"));
3518 * Function: be_get_console_prop
3519 * Description: Determine console device.
3521 * Success - pointer to console setting.
3527 be_get_console_prop(void)
3530 char *console
= NULL
;
3532 if ((dn
= di_init("/", DINFOPROP
)) == DI_NODE_NIL
) {
3533 be_print_err(gettext("be_get_console_prop: "
3534 "di_init() failed\n"));
3538 if (di_prop_lookup_strings(DDI_DEV_T_ANY
, dn
,
3539 "console", &console
) != -1) {
3544 if (console
== NULL
) {
3545 if (di_prop_lookup_strings(DDI_DEV_T_ANY
, dn
,
3546 "output-device", &console
) != -1) {
3548 if (strncmp(console
, "screen", strlen("screen")) == 0)
3549 console
= BE_DEFAULT_CONSOLE
;
3554 * Default console to text
3556 if (console
== NULL
) {
3557 console
= BE_DEFAULT_CONSOLE
;
3564 * Function: be_create_menu
3566 * This function is used if no menu.lst file exists. In
3567 * this case a new file is created and if needed default
3568 * lines are added to the file.
3570 * pool - The name of the pool the menu.lst file is on
3571 * menu_file - The name of the file we're creating.
3572 * menu_fp - A pointer to the file pointer of the file we
3573 * created. This is also used to pass back the file
3574 * pointer to the newly created file.
3575 * mode - the original mode used for the failed attempt to
3576 * non-existent file.
3578 * BE_SUCCESS - Success
3579 * be_errno_t - Failure
3590 be_node_list_t
*be_nodes
= NULL
;
3591 char *menu_path
= NULL
;
3592 char *be_rpool
= NULL
;
3593 char *be_name
= NULL
;
3594 char *console
= NULL
;
3597 if (menu_file
== NULL
|| menu_fp
== NULL
|| mode
== NULL
)
3598 return (BE_ERR_INVAL
);
3600 menu_path
= strdup(menu_file
);
3601 if (menu_path
== NULL
)
3602 return (BE_ERR_NOMEM
);
3604 (void) dirname(menu_path
);
3605 if (*menu_path
== '.') {
3607 return (BE_ERR_BAD_MENU_PATH
);
3609 if (mkdirp(menu_path
,
3610 S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
) == -1 &&
3613 be_print_err(gettext("be_create_menu: Failed to create the %s "
3614 "directory: %s\n"), menu_path
, strerror(errno
));
3615 return (errno_to_be_err(errno
));
3620 * Check to see if this system supports grub
3622 if (be_has_grub()) {
3624 * The grub menu is missing so we need to create it
3625 * and fill in the first few lines.
3627 FILE *temp_fp
= fopen(menu_file
, "a+");
3628 if (temp_fp
== NULL
) {
3630 return (errno_to_be_err(errno
));
3633 if ((console
= be_get_console_prop()) != NULL
) {
3636 * If console is redirected to serial line,
3637 * GRUB splash screen will not be enabled.
3639 if (strncmp(console
, "text", strlen("text")) == 0 ||
3640 strncmp(console
, "graphics",
3641 strlen("graphics")) == 0) {
3643 (void) fprintf(temp_fp
, "%s\n", BE_GRUB_SPLASH
);
3644 (void) fprintf(temp_fp
, "%s\n",
3645 BE_GRUB_FOREGROUND
);
3646 (void) fprintf(temp_fp
, "%s\n",
3647 BE_GRUB_BACKGROUND
);
3648 (void) fprintf(temp_fp
, "%s\n",
3651 be_print_err(gettext("be_create_menu: "
3652 "console on serial line, "
3653 "GRUB splash image will be disabled\n"));
3657 (void) fprintf(temp_fp
, "timeout 30\n");
3658 (void) fclose(temp_fp
);
3662 * The menu file doesn't exist so we need to create a
3665 FILE *temp_fp
= fopen(menu_file
, "w+");
3666 if (temp_fp
== NULL
) {
3668 return (errno_to_be_err(errno
));
3670 (void) fclose(temp_fp
);
3674 * Now we need to add all the BE's back into the the file.
3676 if (_be_list(NULL
, &be_nodes
) == BE_SUCCESS
) {
3677 while (be_nodes
!= NULL
) {
3678 if (strcmp(pool
, be_nodes
->be_rpool
) == 0) {
3679 (void) be_append_menu(be_nodes
->be_node_name
,
3680 be_nodes
->be_rpool
, NULL
, NULL
, NULL
);
3682 if (be_nodes
->be_active_on_boot
) {
3683 be_rpool
= strdup(be_nodes
->be_rpool
);
3684 be_name
= strdup(be_nodes
->be_node_name
);
3687 be_nodes
= be_nodes
->be_next_node
;
3690 be_free_list(be_nodes
);
3693 * Check to see if this system supports grub
3695 if (be_has_grub()) {
3696 int err
= be_change_grub_default(be_name
, be_rpool
);
3697 if (err
!= BE_SUCCESS
)
3700 *menu_fp
= fopen(menu_file
, mode
);
3701 if (*menu_fp
== NULL
)
3702 return (errno_to_be_err(errno
));
3704 return (BE_SUCCESS
);
3708 * Function: be_open_menu
3710 * This function is used it open the menu.lst file. If this
3711 * file does not exist be_create_menu is called to create it
3712 * and the open file pointer is returned. If the file does
3713 * exist it is simply opened using the mode passed in.
3715 * pool - The name of the pool the menu.lst file is on
3716 * menu_file - The name of the file we're opening.
3717 * menu_fp - A pointer to the file pointer of the file we're
3718 * opening. This is also used to pass back the file
3720 * mode - the original mode to be used for opening the menu.lst
3722 * create_menu - If this is true and the menu.lst file does not
3723 * exist we will attempt to re-create it. However
3724 * if it's false the error returned from the fopen
3727 * BE_SUCCESS - Success
3728 * be_errno_t - Failure
3738 boolean_t create_menu
)
3741 boolean_t set_print
= B_FALSE
;
3743 *menu_fp
= fopen(menu_file
, mode
);
3745 if (*menu_fp
== NULL
) {
3746 if (err
== ENOENT
&& create_menu
) {
3747 be_print_err(gettext("be_open_menu: menu.lst "
3748 "file %s does not exist,\n"), menu_file
);
3753 be_print_err(gettext("WARNING: menu.lst "
3754 "file %s does not exist,\n generating "
3755 "a new menu.lst file\n"), menu_file
);
3759 if ((err
= be_create_menu(pool
, menu_file
,
3760 menu_fp
, mode
)) == ENOENT
)
3761 return (BE_ERR_NO_MENU
);
3762 else if (err
!= BE_SUCCESS
)
3764 else if (*menu_fp
== NULL
)
3765 return (BE_ERR_NO_MENU
);
3767 be_print_err(gettext("be_open_menu: failed "
3768 "to open menu.lst file %s\n"), menu_file
);
3770 return (BE_ERR_NO_MENU
);
3772 return (errno_to_be_err(err
));
3775 return (BE_SUCCESS
);