--- old/usr/src/cmd/boot/bootadm/bootadm.c	Mon Feb 11 08:17:17 2019
+++ new/usr/src/cmd/boot/bootadm/bootadm.c	Mon Feb 11 08:17:17 2019
@@ -24,7 +24,7 @@
  * Copyright 2012 Milan Jurik. All rights reserved.
  * Copyright (c) 2015 by Delphix. All rights reserved.
  * Copyright 2016 Toomas Soome <tsoome@me.com>
- * Copyright 2016 Nexenta Systems, Inc.
+ * Copyright 2017 Nexenta Systems, Inc.
  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
  */
 
@@ -160,6 +160,9 @@
 #define	STAGE1			"/boot/grub/stage1"
 #define	STAGE2			"/boot/grub/stage2"
 
+#define	ETC_SYSTEM_DIR		"etc/system.d"
+#define	SELF_ASSEMBLY		"etc/system.d/.self-assembly"
+
 /*
  * Default file attributes
  */
@@ -245,6 +248,7 @@
 static int bam_zfs;
 static int bam_mbr;
 char rootbuf[PATH_MAX] = "/";
+static char self_assembly[PATH_MAX];
 static int bam_update_all;
 static int bam_alt_platform;
 static char *bam_platform;
@@ -283,6 +287,7 @@
 static error_t set_option(menu_t *, char *, char *);
 static error_t set_kernel(menu_t *, menu_cmd_t, char *, char *, size_t);
 static error_t get_kernel(menu_t *, menu_cmd_t, char *, size_t);
+static error_t build_etc_system_dir(char *);
 static char *expand_path(const char *);
 
 static long s_strtol(char *);
@@ -2459,6 +2464,19 @@
 			}
 		}
 
+		/*
+		 * Update self-assembly file if there are changes in
+		 * /etc/system.d directory
+		 */
+		if (strstr(file, ETC_SYSTEM_DIR)) {
+			ret = update_dircache(self_assembly, flags);
+			if (ret == BAM_ERROR) {
+				bam_error(_("directory cache update failed "
+				    "for %s\n"), file);
+				return (-1);
+			}
+		}
+
 		if (bam_verbose) {
 			if (bam_smf_check)
 				bam_print("    %s\n", file);
@@ -3791,7 +3809,132 @@
 	return (BAM_ERROR);
 }
 
+static int
+assemble_systemfile(char *infilename, char *outfilename)
+{
+	char buf[BUFSIZ];
+	FILE *infile, *outfile;
+	size_t n;
+
+	if ((infile = fopen(infilename, "r")) == NULL) {
+		bam_error(_("failed to open file: %s: %s\n"), infilename,
+		    strerror(errno));
+		return (BAM_ERROR);
+	}
+
+	if ((outfile = fopen(outfilename, "a")) == NULL) {
+		bam_error(_("failed to open file: %s: %s\n"), outfilename,
+		    strerror(errno));
+		(void) fclose(infile);
+		return (BAM_ERROR);
+	}
+
+	while ((n = fread(buf, 1, sizeof (buf), infile)) > 0) {
+		if (fwrite(buf, 1, n, outfile) != n) {
+			bam_error(_("failed to write file: %s: %s\n"),
+			    outfilename, strerror(errno));
+			(void) fclose(infile);
+			(void) fclose(outfile);
+			return (BAM_ERROR);
+		}
+	}
+
+	(void) fclose(infile);
+	(void) fclose(outfile);
+
+	return (BAM_SUCCESS);
+}
+
+/*
+ * Concatenate all files (except those starting with a dot)
+ * from /etc/system.d directory into a single /etc/system.d/.self-assembly
+ * file. The kernel reads it before /etc/system file.
+ */
 static error_t
+build_etc_system_dir(char *root)
+{
+	struct dirent **filelist;
+	char path[PATH_MAX], tmpfile[PATH_MAX];
+	int i, files, sysfiles = 0;
+	int ret = BAM_SUCCESS;
+	struct stat st;
+	timespec_t times[2];
+
+	(void) snprintf(path, sizeof (path), "%s/%s", root, ETC_SYSTEM_DIR);
+	(void) snprintf(self_assembly, sizeof (self_assembly),
+	    "%s%s", root, SELF_ASSEMBLY);
+	(void) snprintf(tmpfile, sizeof (tmpfile), "%s.%ld",
+	    self_assembly, (long)getpid());
+
+	if (stat(self_assembly, &st) >= 0 && (st.st_mode & S_IFMT) == S_IFREG) {
+		times[0] = times[1] = st.st_mtim;
+	} else {
+		times[1].tv_nsec = 0;
+	}
+
+	if ((files = scandir(path, &filelist, NULL, alphasort)) < 0) {
+		/* Don't fail the update if <ROOT>/etc/system.d doesn't exist */
+		if (errno == ENOENT)
+			return (BAM_SUCCESS);
+		bam_error(_("can't read %s: %s\n"), path, strerror(errno));
+		return (BAM_ERROR);
+	}
+
+	(void) unlink(tmpfile);
+
+	for (i = 0; i < files; i++) {
+		char	filepath[PATH_MAX];
+		char	*fname;
+
+		fname = filelist[i]->d_name;
+
+		/* skip anything that starts with a dot */
+		if (strncmp(fname, ".", 1) == 0) {
+			free(filelist[i]);
+			continue;
+		}
+
+		if (bam_verbose)
+			bam_print(_("/etc/system.d adding %s/%s\n"),
+			    path, fname);
+
+		(void) snprintf(filepath, sizeof (filepath), "%s/%s",
+		    path, fname);
+
+		if ((assemble_systemfile(filepath, tmpfile)) < 0) {
+			bam_error(_("failed to append file: %s: %s\n"),
+			    filepath, strerror(errno));
+			ret = BAM_ERROR;
+			break;
+		}
+		sysfiles++;
+	}
+
+	if (sysfiles > 0) {
+		if (rename(tmpfile, self_assembly) < 0) {
+			bam_error(_("failed to rename file: %s: %s\n"), tmpfile,
+			    strerror(errno));
+			return (BAM_ERROR);
+		}
+
+		/*
+		 * Use previous attribute times to avoid
+		 * boot archive recreation.
+		 */
+		if (times[1].tv_nsec != 0 &&
+		    utimensat(AT_FDCWD, self_assembly, times, 0) != 0) {
+			bam_error(_("failed to change times: %s\n"),
+			    strerror(errno));
+			return (BAM_ERROR);
+		}
+	} else {
+		(void) unlink(tmpfile);
+		(void) unlink(self_assembly);
+	}
+	return (ret);
+}
+
+static error_t
 create_ramdisk(char *root)
 {
 	char *cmdline, path[PATH_MAX];
@@ -4155,6 +4298,12 @@
 	}
 
 	/*
+	 * Process the /etc/system.d/.self-assembly file.
+	 */
+	if (build_etc_system_dir(bam_root) == BAM_ERROR)
+		return (BAM_ERROR);
+
+	/*
 	 * Now check if an update is really needed.
 	 */
 	ret = update_required(root);
