Print this page
9696 add /etc/system.d support
Portions contributed by: Andy Fiddaman <andy@omniosce.org>
Reviewed by: Hans Rosenfeld <hans.rosenfeld@joyent.com>
Reviewed by: Peter Tribble <peter.tribble@gmail.com>
Reviewed by: C Fraire <cfraire@me.com>
Reviewed by: Toomas Soome <tsoome@me.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  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
  29  */
  30 
  31 /*
  32  * bootadm(1M) is a new utility for managing bootability of
  33  * Solaris *Newboot* environments. It has two primary tasks:
  34  *      - Allow end users to manage bootability of Newboot Solaris instances
  35  *      - Provide services to other subsystems in Solaris (primarily Install)
  36  */
  37 
  38 /* Headers */
  39 #include <stdio.h>
  40 #include <errno.h>
  41 #include <stdlib.h>
  42 #include <string.h>
  43 #include <unistd.h>
  44 #include <sys/types.h>
  45 #include <sys/stat.h>
  46 #include <alloca.h>
  47 #include <stdarg.h>


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



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


 228 static char *prog;
 229 static subcmd_t bam_cmd;
 230 char *bam_root;
 231 int bam_rootlen;
 232 static int bam_root_readonly;
 233 int bam_alt_root;
 234 static int bam_extend = 0;
 235 static int bam_purge = 0;
 236 static char *bam_subcmd;
 237 static char *bam_opt;
 238 static char **bam_argv;
 239 static char *bam_pool;
 240 static int bam_argc;
 241 static int bam_check;
 242 static int bam_saved_check;
 243 static int bam_smf_check;
 244 static int bam_lock_fd = -1;
 245 static int bam_zfs;
 246 static int bam_mbr;
 247 char rootbuf[PATH_MAX] = "/";

 248 static int bam_update_all;
 249 static int bam_alt_platform;
 250 static char *bam_platform;
 251 static char *bam_home_env = NULL;
 252 
 253 /* function prototypes */
 254 static void parse_args_internal(int, char *[]);
 255 static void parse_args(int, char *argv[]);
 256 static error_t bam_menu(char *, char *, int, char *[]);
 257 static error_t bam_install(char *, char *);
 258 static error_t bam_archive(char *, char *);
 259 
 260 static void bam_lock(void);
 261 static void bam_unlock(void);
 262 
 263 static int exec_cmd(char *, filelist_t *);
 264 static error_t read_globals(menu_t *, char *, char *, int);
 265 static int menu_on_bootdisk(char *os_root, char *menu_root);
 266 static menu_t *menu_read(char *);
 267 static error_t menu_write(char *, menu_t *);
 268 static void linelist_free(line_t *);
 269 static void menu_free(menu_t *);
 270 static void filelist_free(filelist_t *);
 271 static error_t list2file(char *, char *, char *, line_t *);
 272 static error_t list_entry(menu_t *, char *, char *);
 273 static error_t list_setting(menu_t *, char *, char *);
 274 static error_t delete_all_entries(menu_t *, char *, char *);
 275 static error_t update_entry(menu_t *mp, char *menu_root, char *opt);
 276 static error_t update_temp(menu_t *mp, char *dummy, char *opt);
 277 
 278 static error_t install_bootloader(void);
 279 static error_t update_archive(char *, char *);
 280 static error_t list_archive(char *, char *);
 281 static error_t update_all(char *, char *);
 282 static error_t read_list(char *, filelist_t *);
 283 static error_t set_option(menu_t *, char *, char *);
 284 static error_t set_kernel(menu_t *, menu_cmd_t, char *, char *, size_t);
 285 static error_t get_kernel(menu_t *, menu_cmd_t, char *, size_t);

 286 static char *expand_path(const char *);
 287 
 288 static long s_strtol(char *);
 289 static int s_fputs(char *, FILE *);
 290 
 291 static int is_amd64(void);
 292 static char *get_machine(void);
 293 static void append_to_flist(filelist_t *, char *);
 294 static int ufs_add_to_sign_list(char *sign);
 295 static error_t synchronize_BE_menu(void);
 296 
 297 #if !defined(_OBP)
 298 static void ucode_install();
 299 #endif
 300 
 301 /* Menu related sub commands */
 302 static subcmd_defn_t menu_subcmds[] = {
 303         "set_option",           OPT_ABSENT,     set_option, 0,  /* PUB */
 304         "list_entry",           OPT_OPTIONAL,   list_entry, 1,  /* PUB */
 305         "delete_all_entries",   OPT_ABSENT,     delete_all_entries, 0, /* PVT */


2442                                                     NEED_UPDATE_SAFE_FILE,
2443                                                     0644);
2444                                                 return (0);
2445                                         }
2446                                 }
2447                                 safefilep = safefilep->next;
2448                         }
2449                 }
2450 
2451                 if (is_flag_on(IS_SPARC_TARGET)) {
2452                         set_dir_flag(NEED_UPDATE);
2453                 } else {
2454                         ret = update_dircache(file, flags);
2455                         if (ret == BAM_ERROR) {
2456                                 bam_error(_("directory cache update failed "
2457                                     "for %s\n"), file);
2458                                 return (-1);
2459                         }
2460                 }
2461 













2462                 if (bam_verbose) {
2463                         if (bam_smf_check)
2464                                 bam_print("    %s\n", file);
2465                         else
2466                                 bam_print(_("    changed %s\n"), file);
2467                 }
2468         }
2469 
2470         return (0);
2471 }
2472 
2473 /*
2474  * Remove a directory path recursively
2475  */
2476 static int
2477 rmdir_r(char *path)
2478 {
2479         struct dirent   *d = NULL;
2480         DIR             *dir = NULL;
2481         char            tpath[PATH_MAX];


3774 
3775 
3776                 ret = create_x86_archive(boot_archive, temp,
3777                     get_cachedir());
3778         }
3779 
3780         if (digest_archive(boot_archive) == BAM_ERROR && bam_verbose)
3781                 bam_print("boot archive hashing failed\n");
3782 
3783         if (ret == BAM_SUCCESS && bam_verbose)
3784                 bam_print("Successfully created %s\n", boot_archive);
3785 
3786         return (ret);
3787 
3788 out_path_err:
3789         bam_error(_("unable to create path on mountpoint %s, path too long\n"),
3790             root);
3791         return (BAM_ERROR);
3792 }
3793 









































3794 static error_t




















































































3795 create_ramdisk(char *root)
3796 {
3797         char *cmdline, path[PATH_MAX];
3798         size_t len;
3799         struct stat sb;
3800         int ret, status = BAM_SUCCESS;
3801 
3802         /* If mkisofs should be used, use it to create the required archives */
3803         if (use_mkisofs()) {
3804                 if (has_cachedir() && is_dir_flag_on(NEED_UPDATE)) {
3805                         ret = mkisofs_archive(root);
3806                         if (ret != 0)
3807                                 status = BAM_ERROR;
3808                 }
3809                 return (status);
3810         } else if (bam_format == BAM_FORMAT_HSFS) {
3811                 bam_error(_("cannot create hsfs archive\n"));
3812                 return (BAM_ERROR);
3813         }
3814 


4138         if (bam_smf_check && !bam_root_readonly && !is_zfs(root))
4139                 return (BAM_SUCCESS);
4140 
4141         /*
4142          * Don't generate archive on ramdisk.
4143          */
4144         if (is_ramdisk(root))
4145                 return (BAM_SUCCESS);
4146 
4147         /*
4148          * root must be writable. This check applies to alternate
4149          * root (-R option); bam_root_readonly applies to '/' only.
4150          * The behaviour translates into being the one of a 'check'.
4151          */
4152         if (!bam_smf_check && !bam_check && is_readonly(root)) {
4153                 set_flag(RDONLY_FSCHK);
4154                 bam_check = 1;
4155         }
4156 
4157         /*






4158          * Now check if an update is really needed.
4159          */
4160         ret = update_required(root);
4161 
4162         /*
4163          * The check command (-n) is *not* a dry run.
4164          * It only checks if the archive is in sync.
4165          * A readonly filesystem has to be considered an error only if an update
4166          * is required.
4167          */
4168         if (bam_nowrite()) {
4169                 if (is_flag_on(RDONLY_FSCHK)) {
4170                         bam_check = bam_saved_check;
4171                         if (ret > 0)
4172                                 bam_error(_("%s filesystem is read-only, "
4173                                     "skipping archives update\n"), root);
4174                         if (bam_update_all)
4175                                 return ((ret != 0) ? BAM_ERROR : BAM_SUCCESS);
4176                 }
4177 




   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  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
  29  */
  30 
  31 /*
  32  * bootadm(1M) is a new utility for managing bootability of
  33  * Solaris *Newboot* environments. It has two primary tasks:
  34  *      - Allow end users to manage bootability of Newboot Solaris instances
  35  *      - Provide services to other subsystems in Solaris (primarily Install)
  36  */
  37 
  38 /* Headers */
  39 #include <stdio.h>
  40 #include <errno.h>
  41 #include <stdlib.h>
  42 #include <string.h>
  43 #include <unistd.h>
  44 #include <sys/types.h>
  45 #include <sys/stat.h>
  46 #include <alloca.h>
  47 #include <stdarg.h>


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


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


2447                                                     NEED_UPDATE_SAFE_FILE,
2448                                                     0644);
2449                                                 return (0);
2450                                         }
2451                                 }
2452                                 safefilep = safefilep->next;
2453                         }
2454                 }
2455 
2456                 if (is_flag_on(IS_SPARC_TARGET)) {
2457                         set_dir_flag(NEED_UPDATE);
2458                 } else {
2459                         ret = update_dircache(file, flags);
2460                         if (ret == BAM_ERROR) {
2461                                 bam_error(_("directory cache update failed "
2462                                     "for %s\n"), file);
2463                                 return (-1);
2464                         }
2465                 }
2466 
2467                 /*
2468                  * Update self-assembly file if there are changes in
2469                  * /etc/system.d directory
2470                  */
2471                 if (strstr(file, ETC_SYSTEM_DIR)) {
2472                         ret = update_dircache(self_assembly, flags);
2473                         if (ret == BAM_ERROR) {
2474                                 bam_error(_("directory cache update failed "
2475                                     "for %s\n"), file);
2476                                 return (-1);
2477                         }
2478                 }
2479 
2480                 if (bam_verbose) {
2481                         if (bam_smf_check)
2482                                 bam_print("    %s\n", file);
2483                         else
2484                                 bam_print(_("    changed %s\n"), file);
2485                 }
2486         }
2487 
2488         return (0);
2489 }
2490 
2491 /*
2492  * Remove a directory path recursively
2493  */
2494 static int
2495 rmdir_r(char *path)
2496 {
2497         struct dirent   *d = NULL;
2498         DIR             *dir = NULL;
2499         char            tpath[PATH_MAX];


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


4281         if (bam_smf_check && !bam_root_readonly && !is_zfs(root))
4282                 return (BAM_SUCCESS);
4283 
4284         /*
4285          * Don't generate archive on ramdisk.
4286          */
4287         if (is_ramdisk(root))
4288                 return (BAM_SUCCESS);
4289 
4290         /*
4291          * root must be writable. This check applies to alternate
4292          * root (-R option); bam_root_readonly applies to '/' only.
4293          * The behaviour translates into being the one of a 'check'.
4294          */
4295         if (!bam_smf_check && !bam_check && is_readonly(root)) {
4296                 set_flag(RDONLY_FSCHK);
4297                 bam_check = 1;
4298         }
4299 
4300         /*
4301          * Process the /etc/system.d/.self-assembly file.
4302          */
4303         if (build_etc_system_dir(bam_root) == BAM_ERROR)
4304                 return (BAM_ERROR);
4305 
4306         /*
4307          * Now check if an update is really needed.
4308          */
4309         ret = update_required(root);
4310 
4311         /*
4312          * The check command (-n) is *not* a dry run.
4313          * It only checks if the archive is in sync.
4314          * A readonly filesystem has to be considered an error only if an update
4315          * is required.
4316          */
4317         if (bam_nowrite()) {
4318                 if (is_flag_on(RDONLY_FSCHK)) {
4319                         bam_check = bam_saved_check;
4320                         if (ret > 0)
4321                                 bam_error(_("%s filesystem is read-only, "
4322                                     "skipping archives update\n"), root);
4323                         if (bam_update_all)
4324                                 return ((ret != 0) ? BAM_ERROR : BAM_SUCCESS);
4325                 }
4326