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 */
29
30 /*
31 * bootadm(1M) is a new utility for managing bootability of
32 * Solaris *Newboot* environments. It has two primary tasks:
33 * - Allow end users to manage bootability of Newboot Solaris instances
34 * - Provide services to other subsystems in Solaris (primarily Install)
35 */
36
37 /* Headers */
38 #include <stdio.h>
39 #include <errno.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <alloca.h>
46 #include <stdarg.h>
47 #include <limits.h>
137 #define CREATE_RAMDISK "boot/solaris/bin/create_ramdisk"
138 #define CREATE_DISKMAP "boot/solaris/bin/create_diskmap"
139 #define EXTRACT_BOOT_FILELIST "boot/solaris/bin/extract_boot_filelist"
140 #define GRUBDISK_MAP "/var/run/solaris_grubdisk.map"
141
142 #define GRUB_slice "/etc/lu/GRUB_slice"
143 #define GRUB_root "/etc/lu/GRUB_root"
144 #define GRUB_fdisk "/etc/lu/GRUB_fdisk"
145 #define GRUB_fdisk_target "/etc/lu/GRUB_fdisk_target"
146 #define FINDROOT_INSTALLGRUB "/etc/lu/installgrub.findroot"
147 #define LULIB "/usr/lib/lu/lulib"
148 #define LULIB_PROPAGATE_FILE "lulib_propagate_file"
149 #define CKSUM "/usr/bin/cksum"
150 #define LU_MENU_CKSUM "/etc/lu/menu.cksum"
151 #define BOOTADM "/sbin/bootadm"
152
153 #define INSTALLGRUB "/sbin/installgrub"
154 #define STAGE1 "/boot/grub/stage1"
155 #define STAGE2 "/boot/grub/stage2"
156
157 /*
158 * Default file attributes
159 */
160 #define DEFAULT_DEV_MODE 0644 /* default permissions */
161 #define DEFAULT_DEV_UID 0 /* user root */
162 #define DEFAULT_DEV_GID 3 /* group sys */
163
164 /*
165 * Menu related
166 * menu_cmd_t and menu_cmds must be kept in sync
167 */
168 char *menu_cmds[] = {
169 "default", /* DEFAULT_CMD */
170 "timeout", /* TIMEOUT_CMD */
171 "title", /* TITLE_CMD */
172 "root", /* ROOT_CMD */
173 "kernel", /* KERNEL_CMD */
174 "kernel$", /* KERNEL_DOLLAR_CMD */
175 "module", /* MODULE_CMD */
176 "module$", /* MODULE_DOLLAR_CMD */
210 static char *prog;
211 static subcmd_t bam_cmd;
212 char *bam_root;
213 int bam_rootlen;
214 static int bam_root_readonly;
215 int bam_alt_root;
216 static int bam_extend = 0;
217 static int bam_purge = 0;
218 static char *bam_subcmd;
219 static char *bam_opt;
220 static char **bam_argv;
221 static char *bam_pool;
222 static int bam_argc;
223 static int bam_check;
224 static int bam_saved_check;
225 static int bam_smf_check;
226 static int bam_lock_fd = -1;
227 static int bam_zfs;
228 static int bam_mbr;
229 char rootbuf[PATH_MAX] = "/";
230 static int bam_update_all;
231 static int bam_alt_platform;
232 static char *bam_platform;
233 static char *bam_home_env = NULL;
234
235 /* function prototypes */
236 static void parse_args_internal(int, char *[]);
237 static void parse_args(int, char *argv[]);
238 static error_t bam_menu(char *, char *, int, char *[]);
239 static error_t bam_install(char *, char *);
240 static error_t bam_archive(char *, char *);
241
242 static void bam_lock(void);
243 static void bam_unlock(void);
244
245 static int exec_cmd(char *, filelist_t *);
246 static error_t read_globals(menu_t *, char *, char *, int);
247 static int menu_on_bootdisk(char *os_root, char *menu_root);
248 static menu_t *menu_read(char *);
249 static error_t menu_write(char *, menu_t *);
250 static void linelist_free(line_t *);
251 static void menu_free(menu_t *);
252 static void filelist_free(filelist_t *);
253 static error_t list2file(char *, char *, char *, line_t *);
254 static error_t list_entry(menu_t *, char *, char *);
255 static error_t list_setting(menu_t *, char *, char *);
256 static error_t delete_all_entries(menu_t *, char *, char *);
257 static error_t update_entry(menu_t *mp, char *menu_root, char *opt);
258 static error_t update_temp(menu_t *mp, char *dummy, char *opt);
259
260 static error_t install_bootloader(void);
261 static error_t update_archive(char *, char *);
262 static error_t list_archive(char *, char *);
263 static error_t update_all(char *, char *);
264 static error_t read_list(char *, filelist_t *);
265 static error_t set_option(menu_t *, char *, char *);
266 static error_t set_kernel(menu_t *, menu_cmd_t, char *, char *, size_t);
267 static error_t get_kernel(menu_t *, menu_cmd_t, char *, size_t);
268 static char *expand_path(const char *);
269
270 static long s_strtol(char *);
271 static int s_fputs(char *, FILE *);
272
273 static int is_amd64(void);
274 static char *get_machine(void);
275 static void append_to_flist(filelist_t *, char *);
276 static int ufs_add_to_sign_list(char *sign);
277 static error_t synchronize_BE_menu(void);
278
279 #if !defined(_OBP)
280 static void ucode_install();
281 #endif
282
283 /* Menu related sub commands */
284 static subcmd_defn_t menu_subcmds[] = {
285 "set_option", OPT_ABSENT, set_option, 0, /* PUB */
286 "list_entry", OPT_OPTIONAL, list_entry, 1, /* PUB */
287 "delete_all_entries", OPT_ABSENT, delete_all_entries, 0, /* PVT */
2375 ret = update_dircache(file, flags);
2376 if (ret == BAM_ERROR) {
2377 bam_error(_("directory cache update "
2378 "failed for %s\n"), file);
2379 return (-1);
2380 }
2381 }
2382
2383 if (bam_verbose)
2384 bam_print(_(" new %s\n"), file);
2385 return (0);
2386 }
2387
2388 /*
2389 * If we got there, the file is already listed as to be included in the
2390 * iso image. We just need to know if we are going to rebuild it or not
2391 */
2392 if (is_flag_on(IS_SPARC_TARGET) &&
2393 is_dir_flag_on(FILE64, NEED_UPDATE) && !bam_nowrite())
2394 return (0);
2395 /*
2396 * File exists in old archive. Check if file has changed
2397 */
2398 assert(sz == 2);
2399 bcopy(value, filestat, sizeof (filestat));
2400
2401 if (flags != FTW_D && (filestat[0] != st->st_size ||
2402 filestat[1] != st->st_mtime)) {
2403 if (bam_smf_check) {
2404 safefilep = safefiles;
2405 while (safefilep != NULL &&
2406 safefilep->name[0] != '\0') {
2407 if (regcomp(&re, safefilep->name,
2408 REG_EXTENDED|REG_NOSUB) == 0) {
2409 status = regexec(&re,
2410 file + bam_rootlen, 0, NULL, 0);
2411 regfree(&re);
2412 if (status == 0) {
2413 (void) creat(
2414 NEED_UPDATE_SAFE_FILE,
2415 0644);
2416 return (0);
2417 }
2418 }
2419 safefilep = safefilep->next;
2420 }
2421 }
2422
2423 if (is_flag_on(IS_SPARC_TARGET)) {
2424 set_dir_flag(FILE64, NEED_UPDATE);
2425 } else {
2426 ret = update_dircache(file, flags);
2427 if (ret == BAM_ERROR) {
2428 bam_error(_("directory cache update failed "
2429 "for %s\n"), file);
2430 return (-1);
2431 }
2432 }
2433
2434 if (bam_verbose) {
2435 if (bam_smf_check)
2436 bam_print(" %s\n", file);
2437 else
2438 bam_print(_(" changed %s\n"), file);
2439 }
2440 }
2441
2442 return (0);
2443 }
2444
2445 /*
2446 * Remove a directory path recursively
2447 */
2448 static int
2449 rmdir_r(char *path)
2450 {
2451 struct dirent *d = NULL;
2452 DIR *dir = NULL;
2453 char tpath[PATH_MAX];
3743
3744
3745 ret = create_x86_archive(boot_archive, temp,
3746 get_cachedir(what));
3747 }
3748
3749 if (digest_archive(boot_archive) == BAM_ERROR && bam_verbose)
3750 bam_print("boot archive hashing failed\n");
3751
3752 if (ret == BAM_SUCCESS && bam_verbose)
3753 bam_print("Successfully created %s\n", boot_archive);
3754
3755 return (ret);
3756
3757 out_path_err:
3758 bam_error(_("unable to create path on mountpoint %s, path too long\n"),
3759 root);
3760 return (BAM_ERROR);
3761 }
3762
3763 static error_t
3764 create_ramdisk(char *root)
3765 {
3766 char *cmdline, path[PATH_MAX];
3767 size_t len;
3768 struct stat sb;
3769 int ret, what, status = BAM_SUCCESS;
3770
3771 /* If there is mkisofs, use it to create the required archives */
3772 if (is_mkisofs()) {
3773 for (what = FILE32; what < CACHEDIR_NUM; what++) {
3774 if (has_cachedir(what) && is_dir_flag_on(what,
3775 NEED_UPDATE)) {
3776 ret = mkisofs_archive(root, what);
3777 if (ret != 0)
3778 status = BAM_ERROR;
3779 }
3780 }
3781 return (status);
3782 }
3783
3928 BAM_DPRINTF(("%s: *IS* a boot archive based Solaris instance: %s\n",
3929 fcn, root));
3930 return (1);
3931 }
3932
3933 /*
3934 * Need to call this for anything that operates on the GRUB menu
3935 * In the x86 live upgrade case the directory /boot/grub may be present
3936 * even on pre-newboot BEs. The authoritative way to check for a GRUB target
3937 * is to check for the presence of the stage2 binary which is present
3938 * only on GRUB targets (even on x86 boot partitions). Checking for the
3939 * presence of the multiboot binary is not correct as it is not present
3940 * on x86 boot partitions.
3941 */
3942 int
3943 is_grub(const char *root)
3944 {
3945 char path[PATH_MAX];
3946 struct stat sb;
3947 void *defp;
3948 boolean_t grub = B_FALSE;
3949 const char *res = NULL;
3950 const char *fcn = "is_grub()";
3951
3952 /* grub is disabled by default */
3953 if ((defp = defopen_r(BE_DEFAULTS)) == NULL) {
3954 return (0);
3955 } else {
3956 res = defread_r(BE_DFLT_BE_HAS_GRUB, defp);
3957 if (res != NULL && res[0] != '\0') {
3958 if (strcasecmp(res, "true") == 0)
3959 grub = B_TRUE;
3960 }
3961 defclose_r(defp);
3962 }
3963
3964 if (grub == B_TRUE) {
3965 (void) snprintf(path, sizeof (path), "%s%s", root, GRUB_STAGE2);
3966 if (stat(path, &sb) == -1) {
3967 BAM_DPRINTF(("%s: Missing GRUB directory: %s\n",
3968 fcn, path));
3969 return (0);
3970 } else
3971 return (1);
3972 }
3973
3974 return (0);
3975 }
3976
3977 int
3978 is_zfs(char *root)
3979 {
3980 struct statvfs vfs;
3981 int ret;
3982 const char *fcn = "is_zfs()";
3983
3984 ret = statvfs(root, &vfs);
3985 INJECT_ERROR1("STATVFS_ZFS", ret = 1);
3986 if (ret != 0) {
3987 bam_error(_("statvfs failed for %s: %s\n"), root,
3988 strerror(errno));
3989 return (0);
3990 }
3991
3992 if (strncmp(vfs.f_basetype, "zfs", strlen("zfs")) == 0) {
4098 if (bam_smf_check && !bam_root_readonly && !is_zfs(root))
4099 return (BAM_SUCCESS);
4100
4101 /*
4102 * Don't generate archive on ramdisk.
4103 */
4104 if (is_ramdisk(root))
4105 return (BAM_SUCCESS);
4106
4107 /*
4108 * root must be writable. This check applies to alternate
4109 * root (-R option); bam_root_readonly applies to '/' only.
4110 * The behaviour translates into being the one of a 'check'.
4111 */
4112 if (!bam_smf_check && !bam_check && is_readonly(root)) {
4113 set_flag(RDONLY_FSCHK);
4114 bam_check = 1;
4115 }
4116
4117 /*
4118 * Now check if an update is really needed.
4119 */
4120 ret = update_required(root);
4121
4122 /*
4123 * The check command (-n) is *not* a dry run.
4124 * It only checks if the archive is in sync.
4125 * A readonly filesystem has to be considered an error only if an update
4126 * is required.
4127 */
4128 if (bam_nowrite()) {
4129 if (is_flag_on(RDONLY_FSCHK)) {
4130 bam_check = bam_saved_check;
4131 if (ret > 0)
4132 bam_error(_("%s filesystem is read-only, "
4133 "skipping archives update\n"), root);
4134 if (bam_update_all)
4135 return ((ret != 0) ? BAM_ERROR : BAM_SUCCESS);
4136 }
4137
|
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 */
29
30 /*
31 * bootadm(1M) is a new utility for managing bootability of
32 * Solaris *Newboot* environments. It has two primary tasks:
33 * - Allow end users to manage bootability of Newboot Solaris instances
34 * - Provide services to other subsystems in Solaris (primarily Install)
35 */
36
37 /* Headers */
38 #include <stdio.h>
39 #include <errno.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <alloca.h>
46 #include <stdarg.h>
47 #include <limits.h>
137 #define CREATE_RAMDISK "boot/solaris/bin/create_ramdisk"
138 #define CREATE_DISKMAP "boot/solaris/bin/create_diskmap"
139 #define EXTRACT_BOOT_FILELIST "boot/solaris/bin/extract_boot_filelist"
140 #define GRUBDISK_MAP "/var/run/solaris_grubdisk.map"
141
142 #define GRUB_slice "/etc/lu/GRUB_slice"
143 #define GRUB_root "/etc/lu/GRUB_root"
144 #define GRUB_fdisk "/etc/lu/GRUB_fdisk"
145 #define GRUB_fdisk_target "/etc/lu/GRUB_fdisk_target"
146 #define FINDROOT_INSTALLGRUB "/etc/lu/installgrub.findroot"
147 #define LULIB "/usr/lib/lu/lulib"
148 #define LULIB_PROPAGATE_FILE "lulib_propagate_file"
149 #define CKSUM "/usr/bin/cksum"
150 #define LU_MENU_CKSUM "/etc/lu/menu.cksum"
151 #define BOOTADM "/sbin/bootadm"
152
153 #define INSTALLGRUB "/sbin/installgrub"
154 #define STAGE1 "/boot/grub/stage1"
155 #define STAGE2 "/boot/grub/stage2"
156
157 #define ETC_SYSTEM_DIR "etc/system.d"
158 #define SELF_ASSEMBLY "etc/system.d/.self-assembly"
159
160 /*
161 * Default file attributes
162 */
163 #define DEFAULT_DEV_MODE 0644 /* default permissions */
164 #define DEFAULT_DEV_UID 0 /* user root */
165 #define DEFAULT_DEV_GID 3 /* group sys */
166
167 /*
168 * Menu related
169 * menu_cmd_t and menu_cmds must be kept in sync
170 */
171 char *menu_cmds[] = {
172 "default", /* DEFAULT_CMD */
173 "timeout", /* TIMEOUT_CMD */
174 "title", /* TITLE_CMD */
175 "root", /* ROOT_CMD */
176 "kernel", /* KERNEL_CMD */
177 "kernel$", /* KERNEL_DOLLAR_CMD */
178 "module", /* MODULE_CMD */
179 "module$", /* MODULE_DOLLAR_CMD */
213 static char *prog;
214 static subcmd_t bam_cmd;
215 char *bam_root;
216 int bam_rootlen;
217 static int bam_root_readonly;
218 int bam_alt_root;
219 static int bam_extend = 0;
220 static int bam_purge = 0;
221 static char *bam_subcmd;
222 static char *bam_opt;
223 static char **bam_argv;
224 static char *bam_pool;
225 static int bam_argc;
226 static int bam_check;
227 static int bam_saved_check;
228 static int bam_smf_check;
229 static int bam_lock_fd = -1;
230 static int bam_zfs;
231 static int bam_mbr;
232 char rootbuf[PATH_MAX] = "/";
233 static char self_assembly[PATH_MAX];
234 static int bam_update_all;
235 static int bam_alt_platform;
236 static char *bam_platform;
237 static char *bam_home_env = NULL;
238
239 /* function prototypes */
240 static void parse_args_internal(int, char *[]);
241 static void parse_args(int, char *argv[]);
242 static error_t bam_menu(char *, char *, int, char *[]);
243 static error_t bam_install(char *, char *);
244 static error_t bam_archive(char *, char *);
245
246 static void bam_lock(void);
247 static void bam_unlock(void);
248
249 static int exec_cmd(char *, filelist_t *);
250 static error_t read_globals(menu_t *, char *, char *, int);
251 static int menu_on_bootdisk(char *os_root, char *menu_root);
252 static menu_t *menu_read(char *);
253 static error_t menu_write(char *, menu_t *);
254 static void linelist_free(line_t *);
255 static void menu_free(menu_t *);
256 static void filelist_free(filelist_t *);
257 static error_t list2file(char *, char *, char *, line_t *);
258 static error_t list_entry(menu_t *, char *, char *);
259 static error_t list_setting(menu_t *, char *, char *);
260 static error_t delete_all_entries(menu_t *, char *, char *);
261 static error_t update_entry(menu_t *mp, char *menu_root, char *opt);
262 static error_t update_temp(menu_t *mp, char *dummy, char *opt);
263
264 static error_t install_bootloader(void);
265 static error_t update_archive(char *, char *);
266 static error_t list_archive(char *, char *);
267 static error_t update_all(char *, char *);
268 static error_t read_list(char *, filelist_t *);
269 static error_t set_option(menu_t *, char *, char *);
270 static error_t set_kernel(menu_t *, menu_cmd_t, char *, char *, size_t);
271 static error_t get_kernel(menu_t *, menu_cmd_t, char *, size_t);
272 static error_t build_etc_system_dir(char *);
273 static char *expand_path(const char *);
274
275 static long s_strtol(char *);
276 static int s_fputs(char *, FILE *);
277
278 static int is_amd64(void);
279 static char *get_machine(void);
280 static void append_to_flist(filelist_t *, char *);
281 static int ufs_add_to_sign_list(char *sign);
282 static error_t synchronize_BE_menu(void);
283
284 #if !defined(_OBP)
285 static void ucode_install();
286 #endif
287
288 /* Menu related sub commands */
289 static subcmd_defn_t menu_subcmds[] = {
290 "set_option", OPT_ABSENT, set_option, 0, /* PUB */
291 "list_entry", OPT_OPTIONAL, list_entry, 1, /* PUB */
292 "delete_all_entries", OPT_ABSENT, delete_all_entries, 0, /* PVT */
2380 ret = update_dircache(file, flags);
2381 if (ret == BAM_ERROR) {
2382 bam_error(_("directory cache update "
2383 "failed for %s\n"), file);
2384 return (-1);
2385 }
2386 }
2387
2388 if (bam_verbose)
2389 bam_print(_(" new %s\n"), file);
2390 return (0);
2391 }
2392
2393 /*
2394 * If we got there, the file is already listed as to be included in the
2395 * iso image. We just need to know if we are going to rebuild it or not
2396 */
2397 if (is_flag_on(IS_SPARC_TARGET) &&
2398 is_dir_flag_on(FILE64, NEED_UPDATE) && !bam_nowrite())
2399 return (0);
2400
2401
2402 /*
2403 * File exists in old archive. Check if file has changed
2404 */
2405 assert(sz == 2);
2406 bcopy(value, filestat, sizeof (filestat));
2407
2408 if (flags != FTW_D && (filestat[0] != st->st_size ||
2409 filestat[1] != st->st_mtime)) {
2410 if (bam_smf_check) {
2411 safefilep = safefiles;
2412 while (safefilep != NULL &&
2413 safefilep->name[0] != '\0') {
2414 if (regcomp(&re, safefilep->name,
2415 REG_EXTENDED|REG_NOSUB) == 0) {
2416 status = regexec(&re,
2417 file + bam_rootlen, 0, NULL, 0);
2418 regfree(&re);
2419 if (status == 0) {
2420 (void) creat(
2421 NEED_UPDATE_SAFE_FILE,
2422 0644);
2423 return (0);
2424 }
2425 }
2426 safefilep = safefilep->next;
2427 }
2428 }
2429
2430 if (is_flag_on(IS_SPARC_TARGET)) {
2431 set_dir_flag(FILE64, NEED_UPDATE);
2432 } else {
2433 ret = update_dircache(file, flags);
2434 if (ret == BAM_ERROR) {
2435 bam_error(_("directory cache update failed "
2436 "for %s\n"), file);
2437 return (-1);
2438 }
2439 }
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
2454 if (bam_verbose) {
2455 if (bam_smf_check)
2456 bam_print(" %s\n", file);
2457 else
2458 bam_print(_(" changed %s\n"), file);
2459 }
2460 }
2461
2462 return (0);
2463 }
2464
2465 /*
2466 * Remove a directory path recursively
2467 */
2468 static int
2469 rmdir_r(char *path)
2470 {
2471 struct dirent *d = NULL;
2472 DIR *dir = NULL;
2473 char tpath[PATH_MAX];
3763
3764
3765 ret = create_x86_archive(boot_archive, temp,
3766 get_cachedir(what));
3767 }
3768
3769 if (digest_archive(boot_archive) == BAM_ERROR && bam_verbose)
3770 bam_print("boot archive hashing failed\n");
3771
3772 if (ret == BAM_SUCCESS && bam_verbose)
3773 bam_print("Successfully created %s\n", boot_archive);
3774
3775 return (ret);
3776
3777 out_path_err:
3778 bam_error(_("unable to create path on mountpoint %s, path too long\n"),
3779 root);
3780 return (BAM_ERROR);
3781 }
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 */
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
3907 create_ramdisk(char *root)
3908 {
3909 char *cmdline, path[PATH_MAX];
3910 size_t len;
3911 struct stat sb;
3912 int ret, what, status = BAM_SUCCESS;
3913
3914 /* If there is mkisofs, use it to create the required archives */
3915 if (is_mkisofs()) {
3916 for (what = FILE32; what < CACHEDIR_NUM; what++) {
3917 if (has_cachedir(what) && is_dir_flag_on(what,
3918 NEED_UPDATE)) {
3919 ret = mkisofs_archive(root, what);
3920 if (ret != 0)
3921 status = BAM_ERROR;
3922 }
3923 }
3924 return (status);
3925 }
3926
4071 BAM_DPRINTF(("%s: *IS* a boot archive based Solaris instance: %s\n",
4072 fcn, root));
4073 return (1);
4074 }
4075
4076 /*
4077 * Need to call this for anything that operates on the GRUB menu
4078 * In the x86 live upgrade case the directory /boot/grub may be present
4079 * even on pre-newboot BEs. The authoritative way to check for a GRUB target
4080 * is to check for the presence of the stage2 binary which is present
4081 * only on GRUB targets (even on x86 boot partitions). Checking for the
4082 * presence of the multiboot binary is not correct as it is not present
4083 * on x86 boot partitions.
4084 */
4085 int
4086 is_grub(const char *root)
4087 {
4088 char path[PATH_MAX];
4089 struct stat sb;
4090 void *defp;
4091 boolean_t grub = B_TRUE;
4092 const char *res = NULL;
4093 const char *fcn = "is_grub()";
4094
4095 /* grub is enabled by default */
4096 if ((defp = defopen_r(BE_DEFAULTS)) != NULL) {
4097 res = defread_r(BE_DFLT_BE_HAS_GRUB, defp);
4098 if (res != NULL && res[0] != '\0') {
4099 if (strcasecmp(res, "false") == 0)
4100 grub = B_FALSE;
4101 }
4102 defclose_r(defp);
4103 }
4104
4105 if (grub == B_TRUE) {
4106 (void) snprintf(path, sizeof (path), "%s%s", root, GRUB_STAGE2);
4107 if (stat(path, &sb) == -1) {
4108 BAM_DPRINTF(("%s: Missing GRUB directory: %s\n",
4109 fcn, path));
4110 return (0);
4111 } else {
4112 return (1);
4113 }
4114 }
4115
4116 return (0);
4117 }
4118
4119 int
4120 is_zfs(char *root)
4121 {
4122 struct statvfs vfs;
4123 int ret;
4124 const char *fcn = "is_zfs()";
4125
4126 ret = statvfs(root, &vfs);
4127 INJECT_ERROR1("STATVFS_ZFS", ret = 1);
4128 if (ret != 0) {
4129 bam_error(_("statvfs failed for %s: %s\n"), root,
4130 strerror(errno));
4131 return (0);
4132 }
4133
4134 if (strncmp(vfs.f_basetype, "zfs", strlen("zfs")) == 0) {
4240 if (bam_smf_check && !bam_root_readonly && !is_zfs(root))
4241 return (BAM_SUCCESS);
4242
4243 /*
4244 * Don't generate archive on ramdisk.
4245 */
4246 if (is_ramdisk(root))
4247 return (BAM_SUCCESS);
4248
4249 /*
4250 * root must be writable. This check applies to alternate
4251 * root (-R option); bam_root_readonly applies to '/' only.
4252 * The behaviour translates into being the one of a 'check'.
4253 */
4254 if (!bam_smf_check && !bam_check && is_readonly(root)) {
4255 set_flag(RDONLY_FSCHK);
4256 bam_check = 1;
4257 }
4258
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 /*
4266 * Now check if an update is really needed.
4267 */
4268 ret = update_required(root);
4269
4270 /*
4271 * The check command (-n) is *not* a dry run.
4272 * It only checks if the archive is in sync.
4273 * A readonly filesystem has to be considered an error only if an update
4274 * is required.
4275 */
4276 if (bam_nowrite()) {
4277 if (is_flag_on(RDONLY_FSCHK)) {
4278 bam_check = bam_saved_check;
4279 if (ret > 0)
4280 bam_error(_("%s filesystem is read-only, "
4281 "skipping archives update\n"), root);
4282 if (bam_update_all)
4283 return ((ret != 0) ? BAM_ERROR : BAM_SUCCESS);
4284 }
4285
|