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>
@@ -22,11 +22,11 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* 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.
*/
/*
* bootadm(1M) is a new utility for managing bootability of
@@ -153,10 +153,13 @@
#define INSTALLGRUB "/sbin/installgrub"
#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
*/
#define DEFAULT_DEV_MODE 0644 /* default permissions */
#define DEFAULT_DEV_UID 0 /* user root */
@@ -226,10 +229,11 @@
static int bam_smf_check;
static int bam_lock_fd = -1;
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;
static char *bam_home_env = NULL;
@@ -264,10 +268,11 @@
static error_t update_all(char *, char *);
static error_t read_list(char *, filelist_t *);
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 *);
static int s_fputs(char *, FILE *);
@@ -2391,10 +2396,12 @@
* iso image. We just need to know if we are going to rebuild it or not
*/
if (is_flag_on(IS_SPARC_TARGET) &&
is_dir_flag_on(FILE64, NEED_UPDATE) && !bam_nowrite())
return (0);
+
+
/*
* File exists in old archive. Check if file has changed
*/
assert(sz == 2);
bcopy(value, filestat, sizeof (filestat));
@@ -2430,10 +2437,23 @@
"for %s\n"), file);
return (-1);
}
}
+ /*
+ * 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);
else
bam_print(_(" changed %s\n"), file);
@@ -3759,11 +3779,134 @@
bam_error(_("unable to create path on mountpoint %s, path too long\n"),
root);
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);
+ }
+
+ 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];
size_t len;
struct stat sb;
@@ -4114,10 +4257,16 @@
set_flag(RDONLY_FSCHK);
bam_check = 1;
}
/*
+ * 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);
/*