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>

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/boot/bootadm/bootadm.c
          +++ new/usr/src/cmd/boot/bootadm/bootadm.c
↓ open down ↓ 16 lines elided ↑ open up ↑
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   * Copyright 2012 Milan Jurik. All rights reserved.
  25   25   * Copyright (c) 2015 by Delphix. All rights reserved.
  26   26   * Copyright 2016 Toomas Soome <tsoome@me.com>
  27      - * Copyright 2016 Nexenta Systems, Inc.
       27 + * Copyright 2017 Nexenta Systems, Inc.
  28   28   */
  29   29  
  30   30  /*
  31   31   * bootadm(1M) is a new utility for managing bootability of
  32   32   * Solaris *Newboot* environments. It has two primary tasks:
  33   33   *      - Allow end users to manage bootability of Newboot Solaris instances
  34   34   *      - Provide services to other subsystems in Solaris (primarily Install)
  35   35   */
  36   36  
  37   37  /* Headers */
↓ open down ↓ 109 lines elided ↑ open up ↑
 147  147  #define LULIB                   "/usr/lib/lu/lulib"
 148  148  #define LULIB_PROPAGATE_FILE    "lulib_propagate_file"
 149  149  #define CKSUM                   "/usr/bin/cksum"
 150  150  #define LU_MENU_CKSUM           "/etc/lu/menu.cksum"
 151  151  #define BOOTADM                 "/sbin/bootadm"
 152  152  
 153  153  #define INSTALLGRUB             "/sbin/installgrub"
 154  154  #define STAGE1                  "/boot/grub/stage1"
 155  155  #define STAGE2                  "/boot/grub/stage2"
 156  156  
      157 +#define ETC_SYSTEM_DIR          "etc/system.d"
      158 +#define SELF_ASSEMBLY           "etc/system.d/.self-assembly"
      159 +
 157  160  /*
 158  161   * Default file attributes
 159  162   */
 160  163  #define DEFAULT_DEV_MODE        0644    /* default permissions */
 161  164  #define DEFAULT_DEV_UID         0       /* user root */
 162  165  #define DEFAULT_DEV_GID         3       /* group sys */
 163  166  
 164  167  /*
 165  168   * Menu related
 166  169   * menu_cmd_t and menu_cmds must be kept in sync
↓ open down ↓ 53 lines elided ↑ open up ↑
 220  223  static char **bam_argv;
 221  224  static char *bam_pool;
 222  225  static int bam_argc;
 223  226  static int bam_check;
 224  227  static int bam_saved_check;
 225  228  static int bam_smf_check;
 226  229  static int bam_lock_fd = -1;
 227  230  static int bam_zfs;
 228  231  static int bam_mbr;
 229  232  char rootbuf[PATH_MAX] = "/";
      233 +static char self_assembly[PATH_MAX];
 230  234  static int bam_update_all;
 231  235  static int bam_alt_platform;
 232  236  static char *bam_platform;
 233  237  static char *bam_home_env = NULL;
 234  238  
 235  239  /* function prototypes */
 236  240  static void parse_args_internal(int, char *[]);
 237  241  static void parse_args(int, char *argv[]);
 238  242  static error_t bam_menu(char *, char *, int, char *[]);
 239  243  static error_t bam_install(char *, char *);
↓ open down ↓ 18 lines elided ↑ open up ↑
 258  262  static error_t update_temp(menu_t *mp, char *dummy, char *opt);
 259  263  
 260  264  static error_t install_bootloader(void);
 261  265  static error_t update_archive(char *, char *);
 262  266  static error_t list_archive(char *, char *);
 263  267  static error_t update_all(char *, char *);
 264  268  static error_t read_list(char *, filelist_t *);
 265  269  static error_t set_option(menu_t *, char *, char *);
 266  270  static error_t set_kernel(menu_t *, menu_cmd_t, char *, char *, size_t);
 267  271  static error_t get_kernel(menu_t *, menu_cmd_t, char *, size_t);
      272 +static error_t build_etc_system_dir(char *);
 268  273  static char *expand_path(const char *);
 269  274  
 270  275  static long s_strtol(char *);
 271  276  static int s_fputs(char *, FILE *);
 272  277  
 273  278  static int is_amd64(void);
 274  279  static char *get_machine(void);
 275  280  static void append_to_flist(filelist_t *, char *);
 276  281  static int ufs_add_to_sign_list(char *sign);
 277  282  static error_t synchronize_BE_menu(void);
↓ open down ↓ 2107 lines elided ↑ open up ↑
2385 2390                  return (0);
2386 2391          }
2387 2392  
2388 2393          /*
2389 2394           * If we got there, the file is already listed as to be included in the
2390 2395           * iso image. We just need to know if we are going to rebuild it or not
2391 2396           */
2392 2397          if (is_flag_on(IS_SPARC_TARGET) &&
2393 2398              is_dir_flag_on(FILE64, NEED_UPDATE) && !bam_nowrite())
2394 2399                  return (0);
     2400 +
     2401 +
2395 2402          /*
2396 2403           * File exists in old archive. Check if file has changed
2397 2404           */
2398 2405          assert(sz == 2);
2399 2406          bcopy(value, filestat, sizeof (filestat));
2400 2407  
2401 2408          if (flags != FTW_D && (filestat[0] != st->st_size ||
2402 2409              filestat[1] != st->st_mtime)) {
2403 2410                  if (bam_smf_check) {
2404 2411                          safefilep = safefiles;
↓ open down ↓ 19 lines elided ↑ open up ↑
2424 2431                          set_dir_flag(FILE64, NEED_UPDATE);
2425 2432                  } else {
2426 2433                          ret = update_dircache(file, flags);
2427 2434                          if (ret == BAM_ERROR) {
2428 2435                                  bam_error(_("directory cache update failed "
2429 2436                                      "for %s\n"), file);
2430 2437                                  return (-1);
2431 2438                          }
2432 2439                  }
2433 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 +
2434 2454                  if (bam_verbose) {
2435 2455                          if (bam_smf_check)
2436 2456                                  bam_print("    %s\n", file);
2437 2457                          else
2438 2458                                  bam_print(_("    changed %s\n"), file);
2439 2459                  }
2440 2460          }
2441 2461  
2442 2462          return (0);
2443 2463  }
↓ open down ↓ 1309 lines elided ↑ open up ↑
3753 3773                  bam_print("Successfully created %s\n", boot_archive);
3754 3774  
3755 3775          return (ret);
3756 3776  
3757 3777  out_path_err:
3758 3778          bam_error(_("unable to create path on mountpoint %s, path too long\n"),
3759 3779              root);
3760 3780          return (BAM_ERROR);
3761 3781  }
3762 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 + */
3763 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
3764 3907  create_ramdisk(char *root)
3765 3908  {
3766 3909          char *cmdline, path[PATH_MAX];
3767 3910          size_t len;
3768 3911          struct stat sb;
3769 3912          int ret, what, status = BAM_SUCCESS;
3770 3913  
3771 3914          /* If there is mkisofs, use it to create the required archives */
3772 3915          if (is_mkisofs()) {
3773 3916                  for (what = FILE32; what < CACHEDIR_NUM; what++) {
↓ open down ↓ 164 lines elided ↑ open up ↑
3938 4081   * only on GRUB targets (even on x86 boot partitions). Checking for the
3939 4082   * presence of the multiboot binary is not correct as it is not present
3940 4083   * on x86 boot partitions.
3941 4084   */
3942 4085  int
3943 4086  is_grub(const char *root)
3944 4087  {
3945 4088          char path[PATH_MAX];
3946 4089          struct stat sb;
3947 4090          void *defp;
3948      -        boolean_t grub = B_FALSE;
     4091 +        boolean_t grub = B_TRUE;
3949 4092          const char *res = NULL;
3950 4093          const char *fcn = "is_grub()";
3951 4094  
3952      -        /* grub is disabled by default */
3953      -        if ((defp = defopen_r(BE_DEFAULTS)) == NULL) {
3954      -                return (0);
3955      -        } else {
     4095 +        /* grub is enabled by default */
     4096 +        if ((defp = defopen_r(BE_DEFAULTS)) != NULL) {
3956 4097                  res = defread_r(BE_DFLT_BE_HAS_GRUB, defp);
3957 4098                  if (res != NULL && res[0] != '\0') {
3958      -                        if (strcasecmp(res, "true") == 0)
3959      -                                grub = B_TRUE;
     4099 +                        if (strcasecmp(res, "false") == 0)
     4100 +                                grub = B_FALSE;
3960 4101                  }
3961 4102                  defclose_r(defp);
3962 4103          }
3963 4104  
3964 4105          if (grub == B_TRUE) {
3965 4106                  (void) snprintf(path, sizeof (path), "%s%s", root, GRUB_STAGE2);
3966 4107                  if (stat(path, &sb) == -1) {
3967 4108                          BAM_DPRINTF(("%s: Missing GRUB directory: %s\n",
3968 4109                              fcn, path));
3969 4110                          return (0);
3970      -                } else
     4111 +                } else {
3971 4112                          return (1);
     4113 +                }
3972 4114          }
3973 4115  
3974 4116          return (0);
3975 4117  }
3976 4118  
3977 4119  int
3978 4120  is_zfs(char *root)
3979 4121  {
3980 4122          struct statvfs          vfs;
3981 4123          int                     ret;
↓ open down ↓ 126 lines elided ↑ open up ↑
4108 4250           * root must be writable. This check applies to alternate
4109 4251           * root (-R option); bam_root_readonly applies to '/' only.
4110 4252           * The behaviour translates into being the one of a 'check'.
4111 4253           */
4112 4254          if (!bam_smf_check && !bam_check && is_readonly(root)) {
4113 4255                  set_flag(RDONLY_FSCHK);
4114 4256                  bam_check = 1;
4115 4257          }
4116 4258  
4117 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 +        /*
4118 4266           * Now check if an update is really needed.
4119 4267           */
4120 4268          ret = update_required(root);
4121 4269  
4122 4270          /*
4123 4271           * The check command (-n) is *not* a dry run.
4124 4272           * It only checks if the archive is in sync.
4125 4273           * A readonly filesystem has to be considered an error only if an update
4126 4274           * is required.
4127 4275           */
↓ open down ↓ 6004 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX