Print this page
9696 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>


   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>


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



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


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

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

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


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


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













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


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









































3764 static error_t


















































































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


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






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




   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>


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


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


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


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


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