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>

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   * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
  29   29   */
  30   30  
  31   31  /*
  32   32   * bootadm(1M) is a new utility for managing bootability of
  33   33   * Solaris *Newboot* environments. It has two primary tasks:
  34   34   *      - Allow end users to manage bootability of Newboot Solaris instances
  35   35   *      - Provide services to other subsystems in Solaris (primarily Install)
  36   36   */
  37   37  
↓ open down ↓ 110 lines elided ↑ open up ↑
 148  148  #define LULIB                   "/usr/lib/lu/lulib"
 149  149  #define LULIB_PROPAGATE_FILE    "lulib_propagate_file"
 150  150  #define CKSUM                   "/usr/bin/cksum"
 151  151  #define LU_MENU_CKSUM           "/etc/lu/menu.cksum"
 152  152  #define BOOTADM                 "/sbin/bootadm"
 153  153  
 154  154  #define INSTALLGRUB             "/sbin/installgrub"
 155  155  #define STAGE1                  "/boot/grub/stage1"
 156  156  #define STAGE2                  "/boot/grub/stage2"
 157  157  
      158 +#define ETC_SYSTEM_DIR          "etc/system.d"
      159 +#define SELF_ASSEMBLY           "etc/system.d/.self-assembly"
      160 +
 158  161  /*
 159  162   * Default file attributes
 160  163   */
 161  164  #define DEFAULT_DEV_MODE        0644    /* default permissions */
 162  165  #define DEFAULT_DEV_UID         0       /* user root */
 163  166  #define DEFAULT_DEV_GID         3       /* group sys */
 164  167  
 165  168  /*
 166  169   * Menu related
 167  170   * menu_cmd_t and menu_cmds must be kept in sync
↓ open down ↓ 53 lines elided ↑ open up ↑
 221  224  static char **bam_argv;
 222  225  static char *bam_pool;
 223  226  static int bam_argc;
 224  227  static int bam_check;
 225  228  static int bam_saved_check;
 226  229  static int bam_smf_check;
 227  230  static int bam_lock_fd = -1;
 228  231  static int bam_zfs;
 229  232  static int bam_mbr;
 230  233  char rootbuf[PATH_MAX] = "/";
      234 +static char self_assembly[PATH_MAX];
 231  235  static int bam_update_all;
 232  236  static int bam_alt_platform;
 233  237  static char *bam_platform;
 234  238  static char *bam_home_env = NULL;
 235  239  
 236  240  /* function prototypes */
 237  241  static void parse_args_internal(int, char *[]);
 238  242  static void parse_args(int, char *argv[]);
 239  243  static error_t bam_menu(char *, char *, int, char *[]);
 240  244  static error_t bam_install(char *, char *);
↓ open down ↓ 18 lines elided ↑ open up ↑
 259  263  static error_t update_temp(menu_t *mp, char *dummy, char *opt);
 260  264  
 261  265  static error_t install_bootloader(void);
 262  266  static error_t update_archive(char *, char *);
 263  267  static error_t list_archive(char *, char *);
 264  268  static error_t update_all(char *, char *);
 265  269  static error_t read_list(char *, filelist_t *);
 266  270  static error_t set_option(menu_t *, char *, char *);
 267  271  static error_t set_kernel(menu_t *, menu_cmd_t, char *, char *, size_t);
 268  272  static error_t get_kernel(menu_t *, menu_cmd_t, char *, size_t);
      273 +static error_t build_etc_system_dir(char *);
 269  274  static char *expand_path(const char *);
 270  275  
 271  276  static long s_strtol(char *);
 272  277  static int s_fputs(char *, FILE *);
 273  278  
 274  279  static int is_amd64(void);
 275  280  static char *get_machine(void);
 276  281  static void append_to_flist(filelist_t *, char *);
 277  282  static int ufs_add_to_sign_list(char *sign);
 278  283  static error_t synchronize_BE_menu(void);
↓ open down ↓ 2107 lines elided ↑ open up ↑
2386 2391                  return (0);
2387 2392          }
2388 2393  
2389 2394          /*
2390 2395           * If we got there, the file is already listed as to be included in the
2391 2396           * iso image. We just need to know if we are going to rebuild it or not
2392 2397           */
2393 2398          if (is_flag_on(IS_SPARC_TARGET) &&
2394 2399              is_dir_flag_on(FILE64, NEED_UPDATE) && !bam_nowrite())
2395 2400                  return (0);
     2401 +
     2402 +
2396 2403          /*
2397 2404           * File exists in old archive. Check if file has changed
2398 2405           */
2399 2406          assert(sz == 2);
2400 2407          bcopy(value, filestat, sizeof (filestat));
2401 2408  
2402 2409          if (flags != FTW_D && (filestat[0] != st->st_size ||
2403 2410              filestat[1] != st->st_mtime)) {
2404 2411                  if (bam_smf_check) {
2405 2412                          safefilep = safefiles;
↓ open down ↓ 19 lines elided ↑ open up ↑
2425 2432                          set_dir_flag(FILE64, NEED_UPDATE);
2426 2433                  } else {
2427 2434                          ret = update_dircache(file, flags);
2428 2435                          if (ret == BAM_ERROR) {
2429 2436                                  bam_error(_("directory cache update failed "
2430 2437                                      "for %s\n"), file);
2431 2438                                  return (-1);
2432 2439                          }
2433 2440                  }
2434 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 +
2435 2455                  if (bam_verbose) {
2436 2456                          if (bam_smf_check)
2437 2457                                  bam_print("    %s\n", file);
2438 2458                          else
2439 2459                                  bam_print(_("    changed %s\n"), file);
2440 2460                  }
2441 2461          }
2442 2462  
2443 2463          return (0);
2444 2464  }
↓ open down ↓ 1309 lines elided ↑ open up ↑
3754 3774                  bam_print("Successfully created %s\n", boot_archive);
3755 3775  
3756 3776          return (ret);
3757 3777  
3758 3778  out_path_err:
3759 3779          bam_error(_("unable to create path on mountpoint %s, path too long\n"),
3760 3780              root);
3761 3781          return (BAM_ERROR);
3762 3782  }
3763 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 + */
3764 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
3765 3908  create_ramdisk(char *root)
3766 3909  {
3767 3910          char *cmdline, path[PATH_MAX];
3768 3911          size_t len;
3769 3912          struct stat sb;
3770 3913          int ret, what, status = BAM_SUCCESS;
3771 3914  
3772 3915          /* If there is mkisofs, use it to create the required archives */
3773 3916          if (is_mkisofs()) {
3774 3917                  for (what = FILE32; what < CACHEDIR_NUM; what++) {
↓ open down ↓ 334 lines elided ↑ open up ↑
4109 4252           * root must be writable. This check applies to alternate
4110 4253           * root (-R option); bam_root_readonly applies to '/' only.
4111 4254           * The behaviour translates into being the one of a 'check'.
4112 4255           */
4113 4256          if (!bam_smf_check && !bam_check && is_readonly(root)) {
4114 4257                  set_flag(RDONLY_FSCHK);
4115 4258                  bam_check = 1;
4116 4259          }
4117 4260  
4118 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 +        /*
4119 4268           * Now check if an update is really needed.
4120 4269           */
4121 4270          ret = update_required(root);
4122 4271  
4123 4272          /*
4124 4273           * The check command (-n) is *not* a dry run.
4125 4274           * It only checks if the archive is in sync.
4126 4275           * A readonly filesystem has to be considered an error only if an update
4127 4276           * is required.
4128 4277           */
↓ open down ↓ 6004 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX