Print this page
NEX-14295 'bootadm update-archive' silently fails if /etc/system.d/ doesn't exist
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Alexander Eremin <alexander.eremin@nexenta.com>
NEX-13052 bootadm misses changes in existing /etc/system.d/ files (message fix)
NEX-13052 bootadm misses changes in existing /etc/system.d/ files
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Alex Deiter <alex.deiter@nexenta.com>
NEX-10318 add /etc/system.d support
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Cynthia Eastham <cynthia.eastham@nexenta.com>
NEX-3025 support root pools on EFI labeled disks
Reviewed by: Jean McCormack <jean.mccormack@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>


   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2012 Milan Jurik. All rights reserved.
  25  * Copyright (c) 2015 by Delphix. All rights reserved.
  26  * Copyright 2016 Toomas Soome <tsoome@me.com>
  27  * Copyright 2016 Nexenta Systems, Inc.
  28  */
  29 
  30 /*
  31  * bootadm(1M) is a new utility for managing bootability of
  32  * Solaris *Newboot* environments. It has two primary tasks:
  33  *      - Allow end users to manage bootability of Newboot Solaris instances
  34  *      - Provide services to other subsystems in Solaris (primarily Install)
  35  */
  36 
  37 /* Headers */
  38 #include <stdio.h>
  39 #include <errno.h>
  40 #include <stdlib.h>
  41 #include <string.h>
  42 #include <unistd.h>
  43 #include <sys/types.h>
  44 #include <sys/stat.h>
  45 #include <alloca.h>
  46 #include <stdarg.h>
  47 #include <limits.h>


 137 #define CREATE_RAMDISK          "boot/solaris/bin/create_ramdisk"
 138 #define CREATE_DISKMAP          "boot/solaris/bin/create_diskmap"
 139 #define EXTRACT_BOOT_FILELIST   "boot/solaris/bin/extract_boot_filelist"
 140 #define GRUBDISK_MAP            "/var/run/solaris_grubdisk.map"
 141 
 142 #define GRUB_slice              "/etc/lu/GRUB_slice"
 143 #define GRUB_root               "/etc/lu/GRUB_root"
 144 #define GRUB_fdisk              "/etc/lu/GRUB_fdisk"
 145 #define GRUB_fdisk_target       "/etc/lu/GRUB_fdisk_target"
 146 #define FINDROOT_INSTALLGRUB    "/etc/lu/installgrub.findroot"
 147 #define LULIB                   "/usr/lib/lu/lulib"
 148 #define LULIB_PROPAGATE_FILE    "lulib_propagate_file"
 149 #define CKSUM                   "/usr/bin/cksum"
 150 #define LU_MENU_CKSUM           "/etc/lu/menu.cksum"
 151 #define BOOTADM                 "/sbin/bootadm"
 152 
 153 #define INSTALLGRUB             "/sbin/installgrub"
 154 #define STAGE1                  "/boot/grub/stage1"
 155 #define STAGE2                  "/boot/grub/stage2"
 156 



 157 /*
 158  * Default file attributes
 159  */
 160 #define DEFAULT_DEV_MODE        0644    /* default permissions */
 161 #define DEFAULT_DEV_UID         0       /* user root */
 162 #define DEFAULT_DEV_GID         3       /* group sys */
 163 
 164 /*
 165  * Menu related
 166  * menu_cmd_t and menu_cmds must be kept in sync
 167  */
 168 char *menu_cmds[] = {
 169         "default",      /* DEFAULT_CMD */
 170         "timeout",      /* TIMEOUT_CMD */
 171         "title",        /* TITLE_CMD */
 172         "root",         /* ROOT_CMD */
 173         "kernel",       /* KERNEL_CMD */
 174         "kernel$",      /* KERNEL_DOLLAR_CMD */
 175         "module",       /* MODULE_CMD */
 176         "module$",      /* MODULE_DOLLAR_CMD */


 210 static char *prog;
 211 static subcmd_t bam_cmd;
 212 char *bam_root;
 213 int bam_rootlen;
 214 static int bam_root_readonly;
 215 int bam_alt_root;
 216 static int bam_extend = 0;
 217 static int bam_purge = 0;
 218 static char *bam_subcmd;
 219 static char *bam_opt;
 220 static char **bam_argv;
 221 static char *bam_pool;
 222 static int bam_argc;
 223 static int bam_check;
 224 static int bam_saved_check;
 225 static int bam_smf_check;
 226 static int bam_lock_fd = -1;
 227 static int bam_zfs;
 228 static int bam_mbr;
 229 char rootbuf[PATH_MAX] = "/";

 230 static int bam_update_all;
 231 static int bam_alt_platform;
 232 static char *bam_platform;
 233 static char *bam_home_env = NULL;
 234 
 235 /* function prototypes */
 236 static void parse_args_internal(int, char *[]);
 237 static void parse_args(int, char *argv[]);
 238 static error_t bam_menu(char *, char *, int, char *[]);
 239 static error_t bam_install(char *, char *);
 240 static error_t bam_archive(char *, char *);
 241 
 242 static void bam_lock(void);
 243 static void bam_unlock(void);
 244 
 245 static int exec_cmd(char *, filelist_t *);
 246 static error_t read_globals(menu_t *, char *, char *, int);
 247 static int menu_on_bootdisk(char *os_root, char *menu_root);
 248 static menu_t *menu_read(char *);
 249 static error_t menu_write(char *, menu_t *);
 250 static void linelist_free(line_t *);
 251 static void menu_free(menu_t *);
 252 static void filelist_free(filelist_t *);
 253 static error_t list2file(char *, char *, char *, line_t *);
 254 static error_t list_entry(menu_t *, char *, char *);
 255 static error_t list_setting(menu_t *, char *, char *);
 256 static error_t delete_all_entries(menu_t *, char *, char *);
 257 static error_t update_entry(menu_t *mp, char *menu_root, char *opt);
 258 static error_t update_temp(menu_t *mp, char *dummy, char *opt);
 259 
 260 static error_t install_bootloader(void);
 261 static error_t update_archive(char *, char *);
 262 static error_t list_archive(char *, char *);
 263 static error_t update_all(char *, char *);
 264 static error_t read_list(char *, filelist_t *);
 265 static error_t set_option(menu_t *, char *, char *);
 266 static error_t set_kernel(menu_t *, menu_cmd_t, char *, char *, size_t);
 267 static error_t get_kernel(menu_t *, menu_cmd_t, char *, size_t);

 268 static char *expand_path(const char *);
 269 
 270 static long s_strtol(char *);
 271 static int s_fputs(char *, FILE *);
 272 
 273 static int is_amd64(void);
 274 static char *get_machine(void);
 275 static void append_to_flist(filelist_t *, char *);
 276 static int ufs_add_to_sign_list(char *sign);
 277 static error_t synchronize_BE_menu(void);
 278 
 279 #if !defined(_OBP)
 280 static void ucode_install();
 281 #endif
 282 
 283 /* Menu related sub commands */
 284 static subcmd_defn_t menu_subcmds[] = {
 285         "set_option",           OPT_ABSENT,     set_option, 0,  /* PUB */
 286         "list_entry",           OPT_OPTIONAL,   list_entry, 1,  /* PUB */
 287         "delete_all_entries",   OPT_ABSENT,     delete_all_entries, 0, /* PVT */


2375                         ret = update_dircache(file, flags);
2376                         if (ret == BAM_ERROR) {
2377                                 bam_error(_("directory cache update "
2378                                     "failed for %s\n"), file);
2379                                 return (-1);
2380                         }
2381                 }
2382 
2383                 if (bam_verbose)
2384                         bam_print(_("    new     %s\n"), file);
2385                 return (0);
2386         }
2387 
2388         /*
2389          * If we got there, the file is already listed as to be included in the
2390          * iso image. We just need to know if we are going to rebuild it or not
2391          */
2392         if (is_flag_on(IS_SPARC_TARGET) &&
2393             is_dir_flag_on(FILE64, NEED_UPDATE) && !bam_nowrite())
2394                 return (0);


2395         /*
2396          * File exists in old archive. Check if file has changed
2397          */
2398         assert(sz == 2);
2399         bcopy(value, filestat, sizeof (filestat));
2400 
2401         if (flags != FTW_D && (filestat[0] != st->st_size ||
2402             filestat[1] != st->st_mtime)) {
2403                 if (bam_smf_check) {
2404                         safefilep = safefiles;
2405                         while (safefilep != NULL &&
2406                             safefilep->name[0] != '\0') {
2407                                 if (regcomp(&re, safefilep->name,
2408                                     REG_EXTENDED|REG_NOSUB) == 0) {
2409                                         status = regexec(&re,
2410                                             file + bam_rootlen, 0, NULL, 0);
2411                                         regfree(&re);
2412                                         if (status == 0) {
2413                                                 (void) creat(
2414                                                     NEED_UPDATE_SAFE_FILE,
2415                                                     0644);
2416                                                 return (0);
2417                                         }
2418                                 }
2419                                 safefilep = safefilep->next;
2420                         }
2421                 }
2422 
2423                 if (is_flag_on(IS_SPARC_TARGET)) {
2424                         set_dir_flag(FILE64, NEED_UPDATE);
2425                 } else {
2426                         ret = update_dircache(file, flags);
2427                         if (ret == BAM_ERROR) {
2428                                 bam_error(_("directory cache update failed "
2429                                     "for %s\n"), file);
2430                                 return (-1);
2431                         }
2432                 }
2433 













2434                 if (bam_verbose) {
2435                         if (bam_smf_check)
2436                                 bam_print("    %s\n", file);
2437                         else
2438                                 bam_print(_("    changed %s\n"), file);
2439                 }
2440         }
2441 
2442         return (0);
2443 }
2444 
2445 /*
2446  * Remove a directory path recursively
2447  */
2448 static int
2449 rmdir_r(char *path)
2450 {
2451         struct dirent   *d = NULL;
2452         DIR             *dir = NULL;
2453         char            tpath[PATH_MAX];


3743 
3744 
3745                 ret = create_x86_archive(boot_archive, temp,
3746                     get_cachedir(what));
3747         }
3748 
3749         if (digest_archive(boot_archive) == BAM_ERROR && bam_verbose)
3750                 bam_print("boot archive hashing failed\n");
3751 
3752         if (ret == BAM_SUCCESS && bam_verbose)
3753                 bam_print("Successfully created %s\n", boot_archive);
3754 
3755         return (ret);
3756 
3757 out_path_err:
3758         bam_error(_("unable to create path on mountpoint %s, path too long\n"),
3759             root);
3760         return (BAM_ERROR);
3761 }
3762 









































3763 static error_t


















































































3764 create_ramdisk(char *root)
3765 {
3766         char *cmdline, path[PATH_MAX];
3767         size_t len;
3768         struct stat sb;
3769         int ret, what, status = BAM_SUCCESS;
3770 
3771         /* If there is mkisofs, use it to create the required archives */
3772         if (is_mkisofs()) {
3773                 for (what = FILE32; what < CACHEDIR_NUM; what++) {
3774                         if (has_cachedir(what) && is_dir_flag_on(what,
3775                             NEED_UPDATE)) {
3776                                 ret = mkisofs_archive(root, what);
3777                                 if (ret != 0)
3778                                         status = BAM_ERROR;
3779                         }
3780                 }
3781                 return (status);
3782         }
3783 


3928         BAM_DPRINTF(("%s: *IS* a boot archive based Solaris instance: %s\n",
3929             fcn, root));
3930         return (1);
3931 }
3932 
3933 /*
3934  * Need to call this for anything that operates on the GRUB menu
3935  * In the x86 live upgrade case the directory /boot/grub may be present
3936  * even on pre-newboot BEs. The authoritative way to check for a GRUB target
3937  * is to check for the presence of the stage2 binary which is present
3938  * only on GRUB targets (even on x86 boot partitions). Checking for the
3939  * presence of the multiboot binary is not correct as it is not present
3940  * on x86 boot partitions.
3941  */
3942 int
3943 is_grub(const char *root)
3944 {
3945         char path[PATH_MAX];
3946         struct stat sb;
3947         void *defp;
3948         boolean_t grub = B_FALSE;
3949         const char *res = NULL;
3950         const char *fcn = "is_grub()";
3951 
3952         /* grub is disabled by default */
3953         if ((defp = defopen_r(BE_DEFAULTS)) == NULL) {
3954                 return (0);
3955         } else {
3956                 res = defread_r(BE_DFLT_BE_HAS_GRUB, defp);
3957                 if (res != NULL && res[0] != '\0') {
3958                         if (strcasecmp(res, "true") == 0)
3959                                 grub = B_TRUE;
3960                 }
3961                 defclose_r(defp);
3962         }
3963 
3964         if (grub == B_TRUE) {
3965                 (void) snprintf(path, sizeof (path), "%s%s", root, GRUB_STAGE2);
3966                 if (stat(path, &sb) == -1) {
3967                         BAM_DPRINTF(("%s: Missing GRUB directory: %s\n",
3968                             fcn, path));
3969                         return (0);
3970                 } else
3971                         return (1);
3972         }

3973 
3974         return (0);
3975 }
3976 
3977 int
3978 is_zfs(char *root)
3979 {
3980         struct statvfs          vfs;
3981         int                     ret;
3982         const char              *fcn = "is_zfs()";
3983 
3984         ret = statvfs(root, &vfs);
3985         INJECT_ERROR1("STATVFS_ZFS", ret = 1);
3986         if (ret != 0) {
3987                 bam_error(_("statvfs failed for %s: %s\n"), root,
3988                     strerror(errno));
3989                 return (0);
3990         }
3991 
3992         if (strncmp(vfs.f_basetype, "zfs", strlen("zfs")) == 0) {


4098         if (bam_smf_check && !bam_root_readonly && !is_zfs(root))
4099                 return (BAM_SUCCESS);
4100 
4101         /*
4102          * Don't generate archive on ramdisk.
4103          */
4104         if (is_ramdisk(root))
4105                 return (BAM_SUCCESS);
4106 
4107         /*
4108          * root must be writable. This check applies to alternate
4109          * root (-R option); bam_root_readonly applies to '/' only.
4110          * The behaviour translates into being the one of a 'check'.
4111          */
4112         if (!bam_smf_check && !bam_check && is_readonly(root)) {
4113                 set_flag(RDONLY_FSCHK);
4114                 bam_check = 1;
4115         }
4116 
4117         /*






4118          * Now check if an update is really needed.
4119          */
4120         ret = update_required(root);
4121 
4122         /*
4123          * The check command (-n) is *not* a dry run.
4124          * It only checks if the archive is in sync.
4125          * A readonly filesystem has to be considered an error only if an update
4126          * is required.
4127          */
4128         if (bam_nowrite()) {
4129                 if (is_flag_on(RDONLY_FSCHK)) {
4130                         bam_check = bam_saved_check;
4131                         if (ret > 0)
4132                                 bam_error(_("%s filesystem is read-only, "
4133                                     "skipping archives update\n"), root);
4134                         if (bam_update_all)
4135                                 return ((ret != 0) ? BAM_ERROR : BAM_SUCCESS);
4136                 }
4137 




   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2012 Milan Jurik. All rights reserved.
  25  * Copyright (c) 2015 by Delphix. All rights reserved.
  26  * Copyright 2016 Toomas Soome <tsoome@me.com>
  27  * Copyright 2017 Nexenta Systems, Inc.
  28  */
  29 
  30 /*
  31  * bootadm(1M) is a new utility for managing bootability of
  32  * Solaris *Newboot* environments. It has two primary tasks:
  33  *      - Allow end users to manage bootability of Newboot Solaris instances
  34  *      - Provide services to other subsystems in Solaris (primarily Install)
  35  */
  36 
  37 /* Headers */
  38 #include <stdio.h>
  39 #include <errno.h>
  40 #include <stdlib.h>
  41 #include <string.h>
  42 #include <unistd.h>
  43 #include <sys/types.h>
  44 #include <sys/stat.h>
  45 #include <alloca.h>
  46 #include <stdarg.h>
  47 #include <limits.h>


 137 #define CREATE_RAMDISK          "boot/solaris/bin/create_ramdisk"
 138 #define CREATE_DISKMAP          "boot/solaris/bin/create_diskmap"
 139 #define EXTRACT_BOOT_FILELIST   "boot/solaris/bin/extract_boot_filelist"
 140 #define GRUBDISK_MAP            "/var/run/solaris_grubdisk.map"
 141 
 142 #define GRUB_slice              "/etc/lu/GRUB_slice"
 143 #define GRUB_root               "/etc/lu/GRUB_root"
 144 #define GRUB_fdisk              "/etc/lu/GRUB_fdisk"
 145 #define GRUB_fdisk_target       "/etc/lu/GRUB_fdisk_target"
 146 #define FINDROOT_INSTALLGRUB    "/etc/lu/installgrub.findroot"
 147 #define LULIB                   "/usr/lib/lu/lulib"
 148 #define LULIB_PROPAGATE_FILE    "lulib_propagate_file"
 149 #define CKSUM                   "/usr/bin/cksum"
 150 #define LU_MENU_CKSUM           "/etc/lu/menu.cksum"
 151 #define BOOTADM                 "/sbin/bootadm"
 152 
 153 #define INSTALLGRUB             "/sbin/installgrub"
 154 #define STAGE1                  "/boot/grub/stage1"
 155 #define STAGE2                  "/boot/grub/stage2"
 156 
 157 #define ETC_SYSTEM_DIR          "etc/system.d"
 158 #define SELF_ASSEMBLY           "etc/system.d/.self-assembly"
 159 
 160 /*
 161  * Default file attributes
 162  */
 163 #define DEFAULT_DEV_MODE        0644    /* default permissions */
 164 #define DEFAULT_DEV_UID         0       /* user root */
 165 #define DEFAULT_DEV_GID         3       /* group sys */
 166 
 167 /*
 168  * Menu related
 169  * menu_cmd_t and menu_cmds must be kept in sync
 170  */
 171 char *menu_cmds[] = {
 172         "default",      /* DEFAULT_CMD */
 173         "timeout",      /* TIMEOUT_CMD */
 174         "title",        /* TITLE_CMD */
 175         "root",         /* ROOT_CMD */
 176         "kernel",       /* KERNEL_CMD */
 177         "kernel$",      /* KERNEL_DOLLAR_CMD */
 178         "module",       /* MODULE_CMD */
 179         "module$",      /* MODULE_DOLLAR_CMD */


 213 static char *prog;
 214 static subcmd_t bam_cmd;
 215 char *bam_root;
 216 int bam_rootlen;
 217 static int bam_root_readonly;
 218 int bam_alt_root;
 219 static int bam_extend = 0;
 220 static int bam_purge = 0;
 221 static char *bam_subcmd;
 222 static char *bam_opt;
 223 static char **bam_argv;
 224 static char *bam_pool;
 225 static int bam_argc;
 226 static int bam_check;
 227 static int bam_saved_check;
 228 static int bam_smf_check;
 229 static int bam_lock_fd = -1;
 230 static int bam_zfs;
 231 static int bam_mbr;
 232 char rootbuf[PATH_MAX] = "/";
 233 static char self_assembly[PATH_MAX];
 234 static int bam_update_all;
 235 static int bam_alt_platform;
 236 static char *bam_platform;
 237 static char *bam_home_env = NULL;
 238 
 239 /* function prototypes */
 240 static void parse_args_internal(int, char *[]);
 241 static void parse_args(int, char *argv[]);
 242 static error_t bam_menu(char *, char *, int, char *[]);
 243 static error_t bam_install(char *, char *);
 244 static error_t bam_archive(char *, char *);
 245 
 246 static void bam_lock(void);
 247 static void bam_unlock(void);
 248 
 249 static int exec_cmd(char *, filelist_t *);
 250 static error_t read_globals(menu_t *, char *, char *, int);
 251 static int menu_on_bootdisk(char *os_root, char *menu_root);
 252 static menu_t *menu_read(char *);
 253 static error_t menu_write(char *, menu_t *);
 254 static void linelist_free(line_t *);
 255 static void menu_free(menu_t *);
 256 static void filelist_free(filelist_t *);
 257 static error_t list2file(char *, char *, char *, line_t *);
 258 static error_t list_entry(menu_t *, char *, char *);
 259 static error_t list_setting(menu_t *, char *, char *);
 260 static error_t delete_all_entries(menu_t *, char *, char *);
 261 static error_t update_entry(menu_t *mp, char *menu_root, char *opt);
 262 static error_t update_temp(menu_t *mp, char *dummy, char *opt);
 263 
 264 static error_t install_bootloader(void);
 265 static error_t update_archive(char *, char *);
 266 static error_t list_archive(char *, char *);
 267 static error_t update_all(char *, char *);
 268 static error_t read_list(char *, filelist_t *);
 269 static error_t set_option(menu_t *, char *, char *);
 270 static error_t set_kernel(menu_t *, menu_cmd_t, char *, char *, size_t);
 271 static error_t get_kernel(menu_t *, menu_cmd_t, char *, size_t);
 272 static error_t build_etc_system_dir(char *);
 273 static char *expand_path(const char *);
 274 
 275 static long s_strtol(char *);
 276 static int s_fputs(char *, FILE *);
 277 
 278 static int is_amd64(void);
 279 static char *get_machine(void);
 280 static void append_to_flist(filelist_t *, char *);
 281 static int ufs_add_to_sign_list(char *sign);
 282 static error_t synchronize_BE_menu(void);
 283 
 284 #if !defined(_OBP)
 285 static void ucode_install();
 286 #endif
 287 
 288 /* Menu related sub commands */
 289 static subcmd_defn_t menu_subcmds[] = {
 290         "set_option",           OPT_ABSENT,     set_option, 0,  /* PUB */
 291         "list_entry",           OPT_OPTIONAL,   list_entry, 1,  /* PUB */
 292         "delete_all_entries",   OPT_ABSENT,     delete_all_entries, 0, /* PVT */


2380                         ret = update_dircache(file, flags);
2381                         if (ret == BAM_ERROR) {
2382                                 bam_error(_("directory cache update "
2383                                     "failed for %s\n"), file);
2384                                 return (-1);
2385                         }
2386                 }
2387 
2388                 if (bam_verbose)
2389                         bam_print(_("    new     %s\n"), file);
2390                 return (0);
2391         }
2392 
2393         /*
2394          * If we got there, the file is already listed as to be included in the
2395          * iso image. We just need to know if we are going to rebuild it or not
2396          */
2397         if (is_flag_on(IS_SPARC_TARGET) &&
2398             is_dir_flag_on(FILE64, NEED_UPDATE) && !bam_nowrite())
2399                 return (0);
2400 
2401 
2402         /*
2403          * File exists in old archive. Check if file has changed
2404          */
2405         assert(sz == 2);
2406         bcopy(value, filestat, sizeof (filestat));
2407 
2408         if (flags != FTW_D && (filestat[0] != st->st_size ||
2409             filestat[1] != st->st_mtime)) {
2410                 if (bam_smf_check) {
2411                         safefilep = safefiles;
2412                         while (safefilep != NULL &&
2413                             safefilep->name[0] != '\0') {
2414                                 if (regcomp(&re, safefilep->name,
2415                                     REG_EXTENDED|REG_NOSUB) == 0) {
2416                                         status = regexec(&re,
2417                                             file + bam_rootlen, 0, NULL, 0);
2418                                         regfree(&re);
2419                                         if (status == 0) {
2420                                                 (void) creat(
2421                                                     NEED_UPDATE_SAFE_FILE,
2422                                                     0644);
2423                                                 return (0);
2424                                         }
2425                                 }
2426                                 safefilep = safefilep->next;
2427                         }
2428                 }
2429 
2430                 if (is_flag_on(IS_SPARC_TARGET)) {
2431                         set_dir_flag(FILE64, NEED_UPDATE);
2432                 } else {
2433                         ret = update_dircache(file, flags);
2434                         if (ret == BAM_ERROR) {
2435                                 bam_error(_("directory cache update failed "
2436                                     "for %s\n"), file);
2437                                 return (-1);
2438                         }
2439                 }
2440 
2441                 /*
2442                  * Update self-assembly file if there are changes in
2443                  * /etc/system.d directory
2444                  */
2445                 if (strstr(file, ETC_SYSTEM_DIR)) {
2446                         ret = update_dircache(self_assembly, flags);
2447                         if (ret == BAM_ERROR) {
2448                                 bam_error(_("directory cache update failed "
2449                                     "for %s\n"), file);
2450                                 return (-1);
2451                         }
2452                 }
2453 
2454                 if (bam_verbose) {
2455                         if (bam_smf_check)
2456                                 bam_print("    %s\n", file);
2457                         else
2458                                 bam_print(_("    changed %s\n"), file);
2459                 }
2460         }
2461 
2462         return (0);
2463 }
2464 
2465 /*
2466  * Remove a directory path recursively
2467  */
2468 static int
2469 rmdir_r(char *path)
2470 {
2471         struct dirent   *d = NULL;
2472         DIR             *dir = NULL;
2473         char            tpath[PATH_MAX];


3763 
3764 
3765                 ret = create_x86_archive(boot_archive, temp,
3766                     get_cachedir(what));
3767         }
3768 
3769         if (digest_archive(boot_archive) == BAM_ERROR && bam_verbose)
3770                 bam_print("boot archive hashing failed\n");
3771 
3772         if (ret == BAM_SUCCESS && bam_verbose)
3773                 bam_print("Successfully created %s\n", boot_archive);
3774 
3775         return (ret);
3776 
3777 out_path_err:
3778         bam_error(_("unable to create path on mountpoint %s, path too long\n"),
3779             root);
3780         return (BAM_ERROR);
3781 }
3782 
3783 static int
3784 assemble_systemfile(char *infilename, char *outfilename)
3785 {
3786         char buf[BUFSIZ];
3787         FILE *infile, *outfile;
3788         size_t n;
3789 
3790         if ((infile = fopen(infilename, "r")) == NULL) {
3791                 bam_error(_("failed to open file: %s: %s\n"), infilename,
3792                     strerror(errno));
3793                 return (BAM_ERROR);
3794         }
3795 
3796         if ((outfile = fopen(outfilename, "a")) == NULL) {
3797                 bam_error(_("failed to open file: %s: %s\n"), outfilename,
3798                     strerror(errno));
3799                 (void) fclose(infile);
3800                 return (BAM_ERROR);
3801         }
3802 
3803         while ((n = fread(buf, 1, sizeof (buf), infile)) > 0) {
3804                 if (fwrite(buf, 1, n, outfile) != n) {
3805                         bam_error(_("failed to write file: %s: %s\n"),
3806                             outfilename, strerror(errno));
3807                         (void) fclose(infile);
3808                         (void) fclose(outfile);
3809                         return (BAM_ERROR);
3810                 }
3811         }
3812 
3813         (void) fclose(infile);
3814         (void) fclose(outfile);
3815 
3816         return (BAM_SUCCESS);
3817 }
3818 
3819 /*
3820  * Concatenate all files (except those starting with a dot)
3821  * from /etc/system.d directory into a single /etc/system.d/.self-assembly
3822  * file. The kernel reads it before /etc/system file.
3823  */
3824 static error_t
3825 build_etc_system_dir(char *root)
3826 {
3827         struct dirent **filelist;
3828         char path[PATH_MAX], tmpfile[PATH_MAX];
3829         int i, files, sysfiles = 0;
3830         int ret = BAM_SUCCESS;
3831         struct stat st;
3832         timespec_t times[2];
3833 
3834         (void) snprintf(path, sizeof (path), "%s/%s", root, ETC_SYSTEM_DIR);
3835         (void) snprintf(self_assembly, sizeof (self_assembly),
3836             "%s%s", root, SELF_ASSEMBLY);
3837         (void) snprintf(tmpfile, sizeof (tmpfile), "%s.%ld",
3838             self_assembly, (long)getpid());
3839 
3840         if (stat(self_assembly, &st) >= 0 && (st.st_mode & S_IFMT) == S_IFREG) {
3841                 times[0] = times[1] = st.st_mtim;
3842         } else {
3843                 times[1].tv_nsec = 0;
3844         }
3845 
3846         if ((files = scandir(path, &filelist, NULL, alphasort)) < 0) {
3847                 /* Don't fail the update if <ROOT>/etc/system.d doesn't exist */
3848                 if (errno == ENOENT)
3849                         return (BAM_SUCCESS);
3850                 bam_error(_("can't read %s: %s\n"), path, strerror(errno));
3851                 return (BAM_ERROR);
3852         }
3853 
3854         for (i = 0; i < files; i++) {
3855                 char    filepath[PATH_MAX];
3856                 char    *fname;
3857 
3858                 fname = filelist[i]->d_name;
3859 
3860                 /* skip anything that starts with a dot */
3861                 if (strncmp(fname, ".", 1) == 0) {
3862                         free(filelist[i]);
3863                         continue;
3864                 }
3865 
3866                 if (bam_verbose)
3867                         bam_print(_("/etc/system.d adding %s/%s\n"),
3868                             path, fname);
3869 
3870                 (void) snprintf(filepath, sizeof (filepath), "%s/%s",
3871                     path, fname);
3872 
3873                 if ((assemble_systemfile(filepath, tmpfile)) < 0) {
3874                         bam_error(_("failed to append file: %s: %s\n"),
3875                             filepath, strerror(errno));
3876                         ret = BAM_ERROR;
3877                         break;
3878                 }
3879                 sysfiles++;
3880         }
3881 
3882         if (sysfiles > 0) {
3883                 if (rename(tmpfile, self_assembly) < 0) {
3884                         bam_error(_("failed to rename file: %s: %s\n"), tmpfile,
3885                             strerror(errno));
3886                         return (BAM_ERROR);
3887                 }
3888 
3889                 /*
3890                  * Use previous attribute times to avoid
3891                  * boot archive recreation.
3892                  */
3893                 if (times[1].tv_nsec != 0 &&
3894                     utimensat(AT_FDCWD, self_assembly, times, 0) != 0) {
3895                         bam_error(_("failed to change times: %s\n"),
3896                             strerror(errno));
3897                         return (BAM_ERROR);
3898                 }
3899         } else {
3900                 (void) unlink(tmpfile);
3901                 (void) unlink(self_assembly);
3902         }
3903         return (ret);
3904 }
3905 
3906 static error_t
3907 create_ramdisk(char *root)
3908 {
3909         char *cmdline, path[PATH_MAX];
3910         size_t len;
3911         struct stat sb;
3912         int ret, what, status = BAM_SUCCESS;
3913 
3914         /* If there is mkisofs, use it to create the required archives */
3915         if (is_mkisofs()) {
3916                 for (what = FILE32; what < CACHEDIR_NUM; what++) {
3917                         if (has_cachedir(what) && is_dir_flag_on(what,
3918                             NEED_UPDATE)) {
3919                                 ret = mkisofs_archive(root, what);
3920                                 if (ret != 0)
3921                                         status = BAM_ERROR;
3922                         }
3923                 }
3924                 return (status);
3925         }
3926 


4071         BAM_DPRINTF(("%s: *IS* a boot archive based Solaris instance: %s\n",
4072             fcn, root));
4073         return (1);
4074 }
4075 
4076 /*
4077  * Need to call this for anything that operates on the GRUB menu
4078  * In the x86 live upgrade case the directory /boot/grub may be present
4079  * even on pre-newboot BEs. The authoritative way to check for a GRUB target
4080  * is to check for the presence of the stage2 binary which is present
4081  * only on GRUB targets (even on x86 boot partitions). Checking for the
4082  * presence of the multiboot binary is not correct as it is not present
4083  * on x86 boot partitions.
4084  */
4085 int
4086 is_grub(const char *root)
4087 {
4088         char path[PATH_MAX];
4089         struct stat sb;
4090         void *defp;
4091         boolean_t grub = B_TRUE;
4092         const char *res = NULL;
4093         const char *fcn = "is_grub()";
4094 
4095         /* grub is enabled by default */
4096         if ((defp = defopen_r(BE_DEFAULTS)) != NULL) {


4097                 res = defread_r(BE_DFLT_BE_HAS_GRUB, defp);
4098                 if (res != NULL && res[0] != '\0') {
4099                         if (strcasecmp(res, "false") == 0)
4100                                 grub = B_FALSE;
4101                 }
4102                 defclose_r(defp);
4103         }
4104 
4105         if (grub == B_TRUE) {
4106                 (void) snprintf(path, sizeof (path), "%s%s", root, GRUB_STAGE2);
4107                 if (stat(path, &sb) == -1) {
4108                         BAM_DPRINTF(("%s: Missing GRUB directory: %s\n",
4109                             fcn, path));
4110                         return (0);
4111                 } else {
4112                         return (1);
4113                 }
4114         }
4115 
4116         return (0);
4117 }
4118 
4119 int
4120 is_zfs(char *root)
4121 {
4122         struct statvfs          vfs;
4123         int                     ret;
4124         const char              *fcn = "is_zfs()";
4125 
4126         ret = statvfs(root, &vfs);
4127         INJECT_ERROR1("STATVFS_ZFS", ret = 1);
4128         if (ret != 0) {
4129                 bam_error(_("statvfs failed for %s: %s\n"), root,
4130                     strerror(errno));
4131                 return (0);
4132         }
4133 
4134         if (strncmp(vfs.f_basetype, "zfs", strlen("zfs")) == 0) {


4240         if (bam_smf_check && !bam_root_readonly && !is_zfs(root))
4241                 return (BAM_SUCCESS);
4242 
4243         /*
4244          * Don't generate archive on ramdisk.
4245          */
4246         if (is_ramdisk(root))
4247                 return (BAM_SUCCESS);
4248 
4249         /*
4250          * root must be writable. This check applies to alternate
4251          * root (-R option); bam_root_readonly applies to '/' only.
4252          * The behaviour translates into being the one of a 'check'.
4253          */
4254         if (!bam_smf_check && !bam_check && is_readonly(root)) {
4255                 set_flag(RDONLY_FSCHK);
4256                 bam_check = 1;
4257         }
4258 
4259         /*
4260          * Process the /etc/system.d/self-assembly file.
4261          */
4262         if (build_etc_system_dir(bam_root) == BAM_ERROR)
4263                 return (BAM_ERROR);
4264 
4265         /*
4266          * Now check if an update is really needed.
4267          */
4268         ret = update_required(root);
4269 
4270         /*
4271          * The check command (-n) is *not* a dry run.
4272          * It only checks if the archive is in sync.
4273          * A readonly filesystem has to be considered an error only if an update
4274          * is required.
4275          */
4276         if (bam_nowrite()) {
4277                 if (is_flag_on(RDONLY_FSCHK)) {
4278                         bam_check = bam_saved_check;
4279                         if (ret > 0)
4280                                 bam_error(_("%s filesystem is read-only, "
4281                                     "skipping archives update\n"), root);
4282                         if (bam_update_all)
4283                                 return ((ret != 0) ? BAM_ERROR : BAM_SUCCESS);
4284                 }
4285