1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
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 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
29 */
30
31 /*
32 * bootadm(8) is a new utility for managing bootability of
33 * Solaris *Newboot* environments. It has two primary tasks:
34 * - Allow end users to manage bootability of Newboot Solaris instances
35 * - Provide services to other subsystems in Solaris (primarily Install)
36 */
37
38 /* Headers */
39 #include <stdio.h>
40 #include <errno.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <alloca.h>
47 #include <stdarg.h>
48 #include <limits.h>
49 #include <signal.h>
50 #include <sys/wait.h>
51 #include <sys/mnttab.h>
52 #include <sys/mntent.h>
53 #include <sys/statvfs.h>
54 #include <libnvpair.h>
55 #include <ftw.h>
56 #include <fcntl.h>
57 #include <strings.h>
58 #include <utime.h>
59 #include <sys/systeminfo.h>
60 #include <sys/dktp/fdisk.h>
61 #include <sys/param.h>
62 #include <dirent.h>
63 #include <ctype.h>
64 #include <libgen.h>
65 #include <sys/sysmacros.h>
66 #include <sys/elf.h>
67 #include <libscf.h>
68 #include <zlib.h>
69 #include <sys/lockfs.h>
70 #include <sys/filio.h>
71 #include <libbe.h>
72 #include <deflt.h>
73 #ifdef i386
74 #include <libfdisk.h>
75 #endif
76
77 #if !defined(_OBP)
78 #include <sys/ucode.h>
79 #endif
80
81 #include <pwd.h>
82 #include <grp.h>
83 #include <device_info.h>
84 #include <sys/vtoc.h>
85 #include <sys/efi_partition.h>
86 #include <regex.h>
87 #include <locale.h>
88 #include <sys/mkdev.h>
89
90 #include "bootadm.h"
91
92 #ifndef TEXT_DOMAIN
93 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
94 #endif /* TEXT_DOMAIN */
95
96 /* Type definitions */
97
98 /* Primary subcmds */
99 typedef enum {
100 BAM_MENU = 3,
101 BAM_ARCHIVE,
102 BAM_INSTALL
103 } subcmd_t;
104
105 #define LINE_INIT 0 /* lineNum initial value */
106 #define ENTRY_INIT -1 /* entryNum initial value */
107 #define ALL_ENTRIES -2 /* selects all boot entries */
108
109 #define PARTNO_NOTFOUND -1 /* Solaris partition not found */
110 #define PARTNO_EFI -2 /* EFI partition table found */
111
112 #define GRUB_DIR "/boot/grub"
113 #define GRUB_STAGE2 GRUB_DIR "/stage2"
114 #define GRUB_MENU "/boot/grub/menu.lst"
115 #define MENU_TMP "/boot/grub/menu.lst.tmp"
116 #define GRUB_BACKUP_MENU "/etc/lu/GRUB_backup_menu"
117 #define RAMDISK_SPECIAL "/devices/ramdisk"
118 #define STUBBOOT "/stubboot"
119 #define MULTIBOOT "/platform/i86pc/multiboot"
120 #define GRUBSIGN_DIR "/boot/grub/bootsign"
121 #define GRUBSIGN_BACKUP "/etc/bootsign"
122 #define GRUBSIGN_UFS_PREFIX "rootfs"
123 #define GRUBSIGN_ZFS_PREFIX "pool_"
124 #define GRUBSIGN_LU_PREFIX "BE_"
125 #define UFS_SIGNATURE_LIST "/var/run/grub_ufs_signatures"
126 #define ZFS_LEGACY_MNTPT "/tmp/bootadm_mnt_zfs_legacy"
127
128 /* SMF */
129 #define BOOT_ARCHIVE_FMRI "system/boot-archive:default"
130 #define SCF_PG_CONFIG "config"
131 #define SCF_PROPERTY_FORMAT "format"
132
133 /* BE defaults */
134 #define BE_DEFAULTS "/etc/default/be"
135 #define BE_DFLT_BE_HAS_GRUB "BE_HAS_GRUB="
136
137 #define BOOTADM_RDONLY_TEST "BOOTADM_RDONLY_TEST"
138
139 /* lock related */
140 #define BAM_LOCK_FILE "/var/run/bootadm.lock"
141 #define LOCK_FILE_PERMS (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
142
143 #define CREATE_RAMDISK "boot/solaris/bin/create_ramdisk"
144 #define CREATE_DISKMAP "boot/solaris/bin/create_diskmap"
145 #define EXTRACT_BOOT_FILELIST "boot/solaris/bin/extract_boot_filelist"
146 #define GRUBDISK_MAP "/var/run/solaris_grubdisk.map"
147
148 #define GRUB_slice "/etc/lu/GRUB_slice"
149 #define GRUB_root "/etc/lu/GRUB_root"
150 #define GRUB_fdisk "/etc/lu/GRUB_fdisk"
151 #define GRUB_fdisk_target "/etc/lu/GRUB_fdisk_target"
152 #define FINDROOT_INSTALLGRUB "/etc/lu/installgrub.findroot"
153 #define LULIB "/usr/lib/lu/lulib"
154 #define LULIB_PROPAGATE_FILE "lulib_propagate_file"
155 #define CKSUM "/usr/bin/cksum"
156 #define LU_MENU_CKSUM "/etc/lu/menu.cksum"
157 #define BOOTADM "/sbin/bootadm"
158
159 #define INSTALLGRUB "/sbin/installgrub"
160 #define STAGE1 "/boot/grub/stage1"
161 #define STAGE2 "/boot/grub/stage2"
162
163 #define ETC_SYSTEM_DIR "etc/system.d"
164 #define SELF_ASSEMBLY "etc/system.d/.self-assembly"
165
166 /*
167 * Default file attributes
168 */
169 #define DEFAULT_DEV_MODE 0644 /* default permissions */
170 #define DEFAULT_DEV_UID 0 /* user root */
171 #define DEFAULT_DEV_GID 3 /* group sys */
172
173 /*
174 * Menu related
175 * menu_cmd_t and menu_cmds must be kept in sync
176 */
177 char *menu_cmds[] = {
178 "default", /* DEFAULT_CMD */
179 "timeout", /* TIMEOUT_CMD */
180 "title", /* TITLE_CMD */
181 "root", /* ROOT_CMD */
182 "kernel", /* KERNEL_CMD */
183 "kernel$", /* KERNEL_DOLLAR_CMD */
184 "module", /* MODULE_CMD */
185 "module$", /* MODULE_DOLLAR_CMD */
186 " ", /* SEP_CMD */
187 "#", /* COMMENT_CMD */
188 "chainloader", /* CHAINLOADER_CMD */
189 "args", /* ARGS_CMD */
190 "findroot", /* FINDROOT_CMD */
191 "bootfs", /* BOOTFS_CMD */
192 NULL
193 };
194
195 char *bam_formats[] = {
196 "hsfs",
197 "ufs",
198 "cpio",
199 "ufs-nocompress",
200 NULL
201 };
202 #define BAM_FORMAT_UNSET -1
203 #define BAM_FORMAT_HSFS 0
204 short bam_format = BAM_FORMAT_UNSET;
205
206 #define OPT_ENTRY_NUM "entry"
207
208 /*
209 * exec_cmd related
210 */
211 typedef struct {
212 line_t *head;
213 line_t *tail;
214 } filelist_t;
215
216 #define BOOT_FILE_LIST "boot/solaris/filelist.ramdisk"
217 #define ETC_FILE_LIST "etc/boot/solaris/filelist.ramdisk"
218
219 #define FILE_STAT "boot/solaris/filestat.ramdisk"
220 #define FILE_STAT_TMP "boot/solaris/filestat.ramdisk.tmp"
221 #define DIR_PERMS (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
222 #define FILE_STAT_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
223
224 #define FILE_STAT_TIMESTAMP "boot/solaris/timestamp.cache"
225
226 /* Globals */
227 int bam_verbose;
228 int bam_force;
229 int bam_debug;
230 int bam_skip_lock;
231 static char *prog;
232 static subcmd_t bam_cmd;
233 char *bam_root;
234 int bam_rootlen;
235 static int bam_root_readonly;
236 int bam_alt_root;
237 static int bam_extend = 0;
238 static int bam_purge = 0;
239 static char *bam_subcmd;
240 static char *bam_opt;
241 static char **bam_argv;
242 static char *bam_pool;
243 static int bam_argc;
244 static int bam_check;
245 static int bam_saved_check;
246 static int bam_smf_check;
247 static int bam_lock_fd = -1;
248 static int bam_zfs;
249 static int bam_mbr;
250 char rootbuf[PATH_MAX] = "/";
251 static char self_assembly[PATH_MAX];
252 static int bam_update_all;
253 static int bam_alt_platform;
254 static char *bam_platform;
255 static char *bam_home_env = NULL;
256
257 /* function prototypes */
258 static void parse_args_internal(int, char *[]);
259 static void parse_args(int, char *argv[]);
260 static error_t bam_menu(char *, char *, int, char *[]);
261 static error_t bam_install(char *, char *);
262 static error_t bam_archive(char *, char *);
263
264 static void bam_lock(void);
265 static void bam_unlock(void);
266
267 static int exec_cmd(char *, filelist_t *);
268 static error_t read_globals(menu_t *, char *, char *, int);
269 static int menu_on_bootdisk(char *os_root, char *menu_root);
270 static menu_t *menu_read(char *);
271 static error_t menu_write(char *, menu_t *);
272 static void linelist_free(line_t *);
273 static void menu_free(menu_t *);
274 static void filelist_free(filelist_t *);
275 static error_t list2file(char *, char *, char *, line_t *);
276 static error_t list_entry(menu_t *, char *, char *);
277 static error_t list_setting(menu_t *, char *, char *);
278 static error_t delete_all_entries(menu_t *, char *, char *);
279 static error_t update_entry(menu_t *mp, char *menu_root, char *opt);
280 static error_t update_temp(menu_t *mp, char *dummy, char *opt);
281
282 static error_t install_bootloader(void);
283 static error_t update_archive(char *, char *);
284 static error_t list_archive(char *, char *);
285 static error_t update_all(char *, char *);
286 static error_t read_list(char *, filelist_t *);
287 static error_t set_option(menu_t *, char *, char *);
288 static error_t set_kernel(menu_t *, menu_cmd_t, char *, char *, size_t);
289 static error_t get_kernel(menu_t *, menu_cmd_t, char *, size_t);
290 static error_t build_etc_system_dir(char *);
291 static char *expand_path(const char *);
292
293 static long s_strtol(char *);
294 static int s_fputs(char *, FILE *);
295
296 static int is_amd64(void);
297 static char *get_machine(void);
298 static void append_to_flist(filelist_t *, char *);
299 static int ufs_add_to_sign_list(char *sign);
300 static error_t synchronize_BE_menu(void);
301
302 #if !defined(_OBP)
303 static void ucode_install();
304 #endif
305
306 /* Menu related sub commands */
307 static subcmd_defn_t menu_subcmds[] = {
308 "set_option", OPT_ABSENT, set_option, 0, /* PUB */
309 "list_entry", OPT_OPTIONAL, list_entry, 1, /* PUB */
310 "delete_all_entries", OPT_ABSENT, delete_all_entries, 0, /* PVT */
311 "update_entry", OPT_REQ, update_entry, 0, /* menu */
312 "update_temp", OPT_OPTIONAL, update_temp, 0, /* reboot */
313 "upgrade", OPT_ABSENT, upgrade_menu, 0, /* menu */
314 "list_setting", OPT_OPTIONAL, list_setting, 1, /* menu */
315 "disable_hypervisor", OPT_ABSENT, cvt_to_metal, 0, /* menu */
316 "enable_hypervisor", OPT_ABSENT, cvt_to_hyper, 0, /* menu */
317 NULL, 0, NULL, 0 /* must be last */
318 };
319
320 /* Archive related sub commands */
321 static subcmd_defn_t arch_subcmds[] = {
322 "update", OPT_ABSENT, update_archive, 0, /* PUB */
323 "update_all", OPT_ABSENT, update_all, 0, /* PVT */
324 "list", OPT_OPTIONAL, list_archive, 1, /* PUB */
325 NULL, 0, NULL, 0 /* must be last */
326 };
327
328 /* Install related sub commands */
329 static subcmd_defn_t inst_subcmds[] = {
330 "install_bootloader", OPT_ABSENT, install_bootloader, 0, /* PUB */
331 NULL, 0, NULL, 0 /* must be last */
332 };
333
334 #define build_path(buf, len, root, prefix, suffix) \
335 snprintf((buf), (len), "%s%s%s%s%s", (root), (prefix), get_machine(), \
336 is_flag_on(IS_SPARC_TARGET) ? "" : "/amd64", (suffix))
337
338 /*
339 * Directory specific flags:
340 * NEED_UPDATE : the specified archive needs to be updated
341 * NO_EXTEND : don't extend the specified archive, but recreate it
342 */
343 #define NEED_UPDATE 0x00000001
344 #define NO_EXTEND 0x00000002
345
346 #define set_dir_flag(f) (walk_arg.dirinfo.flags |= (f))
347 #define unset_dir_flag(f) (walk_arg.dirinfo.flags &= ~(f))
348 #define is_dir_flag_on(f) (walk_arg.dirinfo.flags & (f) ? 1 : 0)
349
350 #define get_cachedir() (walk_arg.dirinfo.cdir_path)
351 #define get_updatedir() (walk_arg.dirinfo.update_path)
352 #define get_count() (walk_arg.dirinfo.count)
353 #define has_cachedir() (walk_arg.dirinfo.has_dir)
354 #define set_dir_present() (walk_arg.dirinfo.has_dir = 1)
355
356 /*
357 * dirinfo_t (specific cache directory information):
358 * cdir_path: path to the archive cache directory
359 * update_path: path to the update directory (contains the files that will be
360 * used to extend the archive)
361 * has_dir: the specified cache directory is active
362 * count: the number of files to update
363 * flags: directory specific flags
364 */
365 typedef struct _dirinfo {
366 char cdir_path[PATH_MAX];
367 char update_path[PATH_MAX];
368 int has_dir;
369 int count;
370 int flags;
371 } dirinfo_t;
372
373 /*
374 * Update flags:
375 * NEED_CACHE_DIR : cache directory is missing and needs to be created
376 * IS_SPARC_TARGET : the target mountpoint is a SPARC environment
377 * UPDATE_ERROR : an error occourred while traversing the list of files
378 * RDONLY_FSCHK : the target filesystem is read-only
379 * RAMDSK_FSCHK : the target filesystem is on a ramdisk
380 */
381 #define NEED_CACHE_DIR 0x00000001
382 #define IS_SPARC_TARGET 0x00000002
383 #define UPDATE_ERROR 0x00000004
384 #define RDONLY_FSCHK 0x00000008
385 #define INVALIDATE_CACHE 0x00000010
386
387 #define is_flag_on(flag) (walk_arg.update_flags & flag ? 1 : 0)
388 #define set_flag(flag) (walk_arg.update_flags |= flag)
389 #define unset_flag(flag) (walk_arg.update_flags &= ~flag)
390
391 /*
392 * struct walk_arg :
393 * update_flags: flags related to the current updating process
394 * new_nvlp/old_nvlp: new and old list of archive-files / attributes pairs
395 * sparcfile: list of file paths for mkisofs -path-list (SPARC only)
396 */
397 static struct {
398 int update_flags;
399 nvlist_t *new_nvlp;
400 nvlist_t *old_nvlp;
401 FILE *sparcfile;
402 dirinfo_t dirinfo;
403 } walk_arg;
404
405 struct safefile {
406 char *name;
407 struct safefile *next;
408 };
409
410 static struct safefile *safefiles = NULL;
411
412 /*
413 * svc:/system/filesystem/usr:default service checks for this file and
414 * does a boot archive update and then reboot the system.
415 */
416 #define NEED_UPDATE_FILE "/etc/svc/volatile/boot_archive_needs_update"
417
418 /*
419 * svc:/system/boot-archive-update:default checks for this file and
420 * updates the boot archive.
421 */
422 #define NEED_UPDATE_SAFE_FILE "/etc/svc/volatile/boot_archive_safefile_update"
423
424 /* Thanks growisofs */
425 #define CD_BLOCK ((off64_t)2048)
426 #define VOLDESC_OFF 16
427 #define DVD_BLOCK (32*1024)
428 #define MAX_IVDs 16
429
430 struct iso_pdesc {
431 unsigned char type [1];
432 unsigned char id [5];
433 unsigned char void1 [80-5-1];
434 unsigned char volume_space_size [8];
435 unsigned char void2 [2048-80-8];
436 };
437
438 /*
439 * COUNT_MAX: maximum number of changed files to justify a multisession update
440 * BA_SIZE_MAX: maximum size of the boot_archive to justify a multisession
441 * update
442 */
443 #define COUNT_MAX 50
444 #define BA_SIZE_MAX (50 * 1024 * 1024)
445
446 #define bam_nowrite() (bam_check || bam_smf_check)
447
448 static int sync_menu = 1; /* whether we need to sync the BE menus */
449
450 static void
usage(void)451 usage(void)
452 {
453 (void) fprintf(stderr, "USAGE:\n");
454
455 /* archive usage */
456 (void) fprintf(stderr,
457 "\t%s update-archive [-vnf] [-R altroot [-p platform]] "
458 "[-F format]\n", prog);
459 (void) fprintf(stderr,
460 "\t%s list-archive [-R altroot [-p platform]]\n", prog);
461 #if defined(_OBP)
462 (void) fprintf(stderr,
463 "\t%s install-bootloader [-fv] [-R altroot] [-P pool]\n", prog);
464 #else
465 (void) fprintf(stderr,
466 "\t%s install-bootloader [-Mfv] [-R altroot] [-P pool]\n", prog);
467 #endif
468 #if !defined(_OBP)
469 /* x86 only */
470 (void) fprintf(stderr, "\t%s set-menu [-R altroot] key=value\n", prog);
471 (void) fprintf(stderr, "\t%s list-menu [-R altroot]\n", prog);
472 #endif
473 }
474
475 /*
476 * Best effort attempt to restore the $HOME value.
477 */
478 static void
restore_env()479 restore_env()
480 {
481 char home_env[PATH_MAX];
482
483 if (bam_home_env) {
484 (void) snprintf(home_env, sizeof (home_env), "HOME=%s",
485 bam_home_env);
486 (void) putenv(home_env);
487 }
488 }
489
490
491 #define SLEEP_TIME 5
492 #define MAX_TRIES 4
493
494 /*
495 * Sanitize the environment in which bootadm will execute its sub-processes
496 * (ex. mkisofs). This is done to prevent those processes from attempting
497 * to access files (ex. .mkisofsrc) or stat paths that might be on NFS
498 * or, potentially, insecure.
499 */
500 static void
sanitize_env()501 sanitize_env()
502 {
503 int stry = 0;
504
505 /* don't depend on caller umask */
506 (void) umask(0022);
507
508 /* move away from a potential unsafe current working directory */
509 while (chdir("/") == -1) {
510 if (errno != EINTR) {
511 bam_print("WARNING: unable to chdir to /");
512 break;
513 }
514 }
515
516 bam_home_env = getenv("HOME");
517 while (bam_home_env != NULL && putenv("HOME=/") == -1) {
518 if (errno == ENOMEM) {
519 /* retry no more than MAX_TRIES times */
520 if (++stry > MAX_TRIES) {
521 bam_print("WARNING: unable to recover from "
522 "system memory pressure... aborting \n");
523 bam_exit(EXIT_FAILURE);
524 }
525 /* memory is tight, try to sleep */
526 bam_print("Attempting to recover from memory pressure: "
527 "sleeping for %d seconds\n", SLEEP_TIME * stry);
528 (void) sleep(SLEEP_TIME * stry);
529 } else {
530 bam_print("WARNING: unable to sanitize HOME\n");
531 }
532 }
533 }
534
535 int
main(int argc,char * argv[])536 main(int argc, char *argv[])
537 {
538 error_t ret = BAM_SUCCESS;
539
540 (void) setlocale(LC_ALL, "");
541 (void) textdomain(TEXT_DOMAIN);
542
543 if ((prog = strrchr(argv[0], '/')) == NULL) {
544 prog = argv[0];
545 } else {
546 prog++;
547 }
548
549 INJECT_ERROR1("ASSERT_ON", assert(0))
550
551 sanitize_env();
552
553 parse_args(argc, argv);
554
555 switch (bam_cmd) {
556 case BAM_MENU:
557 if (is_grub(bam_alt_root ? bam_root : "/")) {
558 ret = bam_menu(bam_subcmd, bam_opt,
559 bam_argc, bam_argv);
560 } else {
561 ret = bam_loader_menu(bam_subcmd, bam_opt,
562 bam_argc, bam_argv);
563 }
564 break;
565 case BAM_ARCHIVE:
566 ret = bam_archive(bam_subcmd, bam_opt);
567 break;
568 case BAM_INSTALL:
569 ret = bam_install(bam_subcmd, bam_opt);
570 break;
571 default:
572 usage();
573 bam_exit(1);
574 }
575
576 if (ret != BAM_SUCCESS)
577 bam_exit((ret == BAM_NOCHANGE) ? 2 : 1);
578
579 bam_unlock();
580 return (0);
581 }
582
583 /*
584 * Equivalence of public and internal commands:
585 * update-archive -- -a update
586 * list-archive -- -a list
587 * set-menu -- -m set_option
588 * list-menu -- -m list_entry
589 * update-menu -- -m update_entry
590 * install-bootloader -- -i install_bootloader
591 */
592 static struct cmd_map {
593 char *bam_cmdname;
594 int bam_cmd;
595 char *bam_subcmd;
596 } cmd_map[] = {
597 { "update-archive", BAM_ARCHIVE, "update"},
598 { "list-archive", BAM_ARCHIVE, "list"},
599 { "set-menu", BAM_MENU, "set_option"},
600 { "list-menu", BAM_MENU, "list_entry"},
601 { "update-menu", BAM_MENU, "update_entry"},
602 { "install-bootloader", BAM_INSTALL, "install_bootloader"},
603 { NULL, 0, NULL}
604 };
605
606 /*
607 * Commands syntax published in bootadm(8) are parsed here
608 */
609 static void
parse_args(int argc,char * argv[])610 parse_args(int argc, char *argv[])
611 {
612 struct cmd_map *cmp = cmd_map;
613
614 /* command conforming to the final spec */
615 if (argc > 1 && argv[1][0] != '-') {
616 /*
617 * Map commands to internal table.
618 */
619 while (cmp->bam_cmdname) {
620 if (strcmp(argv[1], cmp->bam_cmdname) == 0) {
621 bam_cmd = cmp->bam_cmd;
622 bam_subcmd = cmp->bam_subcmd;
623 break;
624 }
625 cmp++;
626 }
627 if (cmp->bam_cmdname == NULL) {
628 usage();
629 bam_exit(1);
630 }
631 argc--;
632 argv++;
633 }
634
635 parse_args_internal(argc, argv);
636 }
637
638 /*
639 * A combination of public and private commands are parsed here.
640 * The internal syntax and the corresponding functionality are:
641 * -a update -- update-archive
642 * -a list -- list-archive
643 * -a update_all -- (reboot to sync all mnted OS archive)
644 * -i install_bootloader -- install-bootloader
645 * -m update_entry -- update-menu
646 * -m list_entry -- list-menu
647 * -m update_temp -- (reboot -- [boot-args])
648 * -m delete_all_entries -- (called from install)
649 * -m enable_hypervisor [args] -- cvt_to_hyper
650 * -m disable_hypervisor -- cvt_to_metal
651 * -m list_setting [entry] [value] -- list_setting
652 *
653 * A set of private flags is there too:
654 * -Q -- purge the cache directories and rebuild them
655 * -e -- use the (faster) archive update approach (used by
656 * reboot)
657 * -L -- skip locking
658 */
659 static void
parse_args_internal(int argc,char * argv[])660 parse_args_internal(int argc, char *argv[])
661 {
662 int c, i, error;
663 extern char *optarg;
664 extern int optind, opterr;
665 #if defined(_OBP)
666 const char *optstring = "a:d:fF:i:m:no:veQCLR:p:P:XZ";
667 #else
668 const char *optstring = "a:d:fF:i:m:no:veQCMLR:p:P:XZ";
669 #endif
670
671 /* Suppress error message from getopt */
672 opterr = 0;
673
674 error = 0;
675 while ((c = getopt(argc, argv, optstring)) != -1) {
676 switch (c) {
677 case 'a':
678 if (bam_cmd) {
679 error = 1;
680 bam_error(
681 _("multiple commands specified: -%c\n"), c);
682 }
683 bam_cmd = BAM_ARCHIVE;
684 bam_subcmd = optarg;
685 break;
686 case 'd':
687 if (bam_debug) {
688 error = 1;
689 bam_error(
690 _("duplicate options specified: -%c\n"), c);
691 }
692 bam_debug = s_strtol(optarg);
693 break;
694 case 'f':
695 bam_force = 1;
696 break;
697 case 'F':
698 if (bam_format != BAM_FORMAT_UNSET) {
699 error = 1;
700 bam_error(
701 _("multiple formats specified: -%c\n"), c);
702 }
703 for (i = 0; bam_formats[i] != NULL; i++) {
704 if (strcmp(bam_formats[i], optarg) == 0) {
705 bam_format = i;
706 break;
707 }
708 }
709 if (bam_format == BAM_FORMAT_UNSET) {
710 error = 1;
711 bam_error(
712 _("unknown format specified: -%c %s\n"),
713 c, optarg);
714 }
715 break;
716 case 'Q':
717 bam_purge = 1;
718 break;
719 case 'L':
720 bam_skip_lock = 1;
721 break;
722 case 'i':
723 if (bam_cmd) {
724 error = 1;
725 bam_error(
726 _("multiple commands specified: -%c\n"), c);
727 }
728 bam_cmd = BAM_INSTALL;
729 bam_subcmd = optarg;
730 break;
731 case 'm':
732 if (bam_cmd) {
733 error = 1;
734 bam_error(
735 _("multiple commands specified: -%c\n"), c);
736 }
737 bam_cmd = BAM_MENU;
738 bam_subcmd = optarg;
739 break;
740 #if !defined(_OBP)
741 case 'M':
742 bam_mbr = 1;
743 break;
744 #endif
745 case 'n':
746 bam_check = 1;
747 /*
748 * We save the original value of bam_check. The new
749 * approach in case of a read-only filesystem is to
750 * behave as a check, so we need a way to restore the
751 * original value after the evaluation of the read-only
752 * filesystem has been done.
753 * Even if we don't allow at the moment a check with
754 * update_all, this approach is more robust than
755 * simply resetting bam_check to zero.
756 */
757 bam_saved_check = 1;
758 break;
759 case 'o':
760 if (bam_opt) {
761 error = 1;
762 bam_error(
763 _("duplicate options specified: -%c\n"), c);
764 }
765 bam_opt = optarg;
766 break;
767 case 'v':
768 bam_verbose = 1;
769 break;
770 case 'C':
771 bam_smf_check = 1;
772 break;
773 case 'P':
774 if (bam_pool != NULL) {
775 error = 1;
776 bam_error(
777 _("duplicate options specified: -%c\n"), c);
778 }
779 bam_pool = optarg;
780 break;
781 case 'R':
782 if (bam_root) {
783 error = 1;
784 bam_error(
785 _("duplicate options specified: -%c\n"), c);
786 break;
787 } else if (realpath(optarg, rootbuf) == NULL) {
788 error = 1;
789 bam_error(_("cannot resolve path %s: %s\n"),
790 optarg, strerror(errno));
791 break;
792 }
793 bam_alt_root = 1;
794 bam_root = rootbuf;
795 bam_rootlen = strlen(rootbuf);
796 break;
797 case 'p':
798 bam_alt_platform = 1;
799 bam_platform = optarg;
800 if ((strcmp(bam_platform, "i86pc") != 0) &&
801 (strcmp(bam_platform, "sun4u") != 0) &&
802 (strcmp(bam_platform, "sun4v") != 0)) {
803 error = 1;
804 bam_error(_("invalid platform %s - must be "
805 "one of sun4u, sun4v or i86pc\n"),
806 bam_platform);
807 }
808 break;
809 case 'X':
810 bam_is_hv = BAM_HV_PRESENT;
811 break;
812 case 'Z':
813 bam_zfs = 1;
814 break;
815 case 'e':
816 bam_extend = 1;
817 break;
818 case '?':
819 error = 1;
820 bam_error(_("invalid option or missing option "
821 "argument: -%c\n"), optopt);
822 break;
823 default :
824 error = 1;
825 bam_error(_("invalid option or missing option "
826 "argument: -%c\n"), c);
827 break;
828 }
829 }
830
831 /*
832 * An alternate platform requires an alternate root
833 */
834 if (bam_alt_platform && bam_alt_root == 0) {
835 usage();
836 bam_exit(0);
837 }
838
839 /*
840 * A command option must be specfied
841 */
842 if (!bam_cmd) {
843 if (bam_opt && strcmp(bam_opt, "all") == 0) {
844 usage();
845 bam_exit(0);
846 }
847 bam_error(_("a command option must be specified\n"));
848 error = 1;
849 }
850
851 if (error) {
852 usage();
853 bam_exit(1);
854 }
855
856 if (optind > argc) {
857 bam_error(_("Internal error: %s\n"), "parse_args");
858 bam_exit(1);
859 } else if (optind < argc) {
860 bam_argv = &argv[optind];
861 bam_argc = argc - optind;
862 }
863
864 /*
865 * mbr and pool are options for install_bootloader
866 */
867 if (bam_cmd != BAM_INSTALL && (bam_mbr || bam_pool != NULL)) {
868 usage();
869 bam_exit(0);
870 }
871
872 /*
873 * -n implies verbose mode
874 */
875 if (bam_check)
876 bam_verbose = 1;
877 }
878
879 error_t
check_subcmd_and_options(char * subcmd,char * opt,subcmd_defn_t * table,error_t (** fp)())880 check_subcmd_and_options(
881 char *subcmd,
882 char *opt,
883 subcmd_defn_t *table,
884 error_t (**fp)())
885 {
886 int i;
887
888 if (subcmd == NULL) {
889 bam_error(_("this command requires a sub-command\n"));
890 return (BAM_ERROR);
891 }
892
893 if (strcmp(subcmd, "set_option") == 0) {
894 if (bam_argc == 0 || bam_argv == NULL || bam_argv[0] == NULL) {
895 bam_error(_("missing argument for sub-command\n"));
896 usage();
897 return (BAM_ERROR);
898 } else if (bam_argc > 1 || bam_argv[1] != NULL) {
899 bam_error(_("invalid trailing arguments\n"));
900 usage();
901 return (BAM_ERROR);
902 }
903 } else if (strcmp(subcmd, "update_all") == 0) {
904 /*
905 * The only option we accept for the "update_all"
906 * subcmd is "fastboot".
907 */
908 if (bam_argc > 1 || (bam_argc == 1 &&
909 strcmp(bam_argv[0], "fastboot") != 0)) {
910 bam_error(_("invalid trailing arguments\n"));
911 usage();
912 return (BAM_ERROR);
913 }
914 if (bam_argc == 1)
915 sync_menu = 0;
916 } else if (((strcmp(subcmd, "enable_hypervisor") != 0) &&
917 (strcmp(subcmd, "list_setting") != 0)) && (bam_argc || bam_argv)) {
918 /*
919 * Of the remaining subcommands, only "enable_hypervisor" and
920 * "list_setting" take trailing arguments.
921 */
922 bam_error(_("invalid trailing arguments\n"));
923 usage();
924 return (BAM_ERROR);
925 }
926
927 if (bam_root == NULL) {
928 bam_root = rootbuf;
929 bam_rootlen = 1;
930 }
931
932 /* verify that subcmd is valid */
933 for (i = 0; table[i].subcmd != NULL; i++) {
934 if (strcmp(table[i].subcmd, subcmd) == 0)
935 break;
936 }
937
938 if (table[i].subcmd == NULL) {
939 bam_error(_("invalid sub-command specified: %s\n"), subcmd);
940 return (BAM_ERROR);
941 }
942
943 if (table[i].unpriv == 0 && geteuid() != 0) {
944 bam_error(_("you must be root to run this command\n"));
945 return (BAM_ERROR);
946 }
947
948 /*
949 * Currently only privileged commands need a lock
950 */
951 if (table[i].unpriv == 0)
952 bam_lock();
953
954 /* subcmd verifies that opt is appropriate */
955 if (table[i].option != OPT_OPTIONAL) {
956 if ((table[i].option == OPT_REQ) ^ (opt != NULL)) {
957 if (opt)
958 bam_error(_("this sub-command (%s) does not "
959 "take options\n"), subcmd);
960 else
961 bam_error(_("an option is required for this "
962 "sub-command: %s\n"), subcmd);
963 return (BAM_ERROR);
964 }
965 }
966
967 *fp = table[i].handler;
968
969 return (BAM_SUCCESS);
970 }
971
972 /*
973 * NOTE: A single "/" is also considered a trailing slash and will
974 * be deleted.
975 */
976 void
elide_trailing_slash(const char * src,char * dst,size_t dstsize)977 elide_trailing_slash(const char *src, char *dst, size_t dstsize)
978 {
979 size_t dstlen;
980
981 assert(src);
982 assert(dst);
983
984 (void) strlcpy(dst, src, dstsize);
985
986 dstlen = strlen(dst);
987 if (dst[dstlen - 1] == '/') {
988 dst[dstlen - 1] = '\0';
989 }
990 }
991
992 static int
is_safe_exec(char * path)993 is_safe_exec(char *path)
994 {
995 struct stat sb;
996
997 if (lstat(path, &sb) != 0) {
998 bam_error(_("stat of file failed: %s: %s\n"), path,
999 strerror(errno));
1000 return (BAM_ERROR);
1001 }
1002
1003 if (!S_ISREG(sb.st_mode)) {
1004 bam_error(_("%s is not a regular file, skipping\n"), path);
1005 return (BAM_ERROR);
1006 }
1007
1008 if (sb.st_uid != getuid()) {
1009 bam_error(_("%s is not owned by %d, skipping\n"),
1010 path, getuid());
1011 return (BAM_ERROR);
1012 }
1013
1014 if (sb.st_mode & S_IWOTH || sb.st_mode & S_IWGRP) {
1015 bam_error(_("%s is others or group writable, skipping\n"),
1016 path);
1017 return (BAM_ERROR);
1018 }
1019
1020 return (BAM_SUCCESS);
1021 }
1022
1023 static error_t
list_setting(menu_t * mp,char * which,char * setting)1024 list_setting(menu_t *mp, char *which, char *setting)
1025 {
1026 line_t *lp;
1027 entry_t *ent;
1028
1029 char *p = which;
1030 int entry;
1031
1032 int found;
1033
1034 assert(which);
1035 assert(setting);
1036
1037 if (*which != '\0') {
1038 /*
1039 * If "which" is not a number, assume it's a setting we want
1040 * to look for and so set up the routine to look for "which"
1041 * in the default entry.
1042 */
1043 while (*p != '\0')
1044 if (!(isdigit((int)*p++))) {
1045 setting = which;
1046 which = mp->curdefault->arg;
1047 break;
1048 }
1049 } else {
1050 which = mp->curdefault->arg;
1051 }
1052
1053 entry = atoi(which);
1054
1055 for (ent = mp->entries; ((ent != NULL) && (ent->entryNum != entry));
1056 ent = ent->next)
1057 ;
1058
1059 if (!ent) {
1060 bam_error(_("no matching entry found\n"));
1061 return (BAM_ERROR);
1062 }
1063
1064 found = (*setting == '\0');
1065
1066 for (lp = ent->start; lp != NULL; lp = lp->next) {
1067 if ((*setting == '\0') && (lp->flags != BAM_COMMENT))
1068 bam_print("%s\n", lp->line);
1069 else if (lp->cmd != NULL && strcmp(setting, lp->cmd) == 0) {
1070 bam_print("%s\n", lp->arg);
1071 found = 1;
1072 }
1073
1074 if (lp == ent->end)
1075 break;
1076 }
1077
1078 if (!found) {
1079 bam_error(_("no matching entry found\n"));
1080 return (BAM_ERROR);
1081 }
1082
1083 return (BAM_SUCCESS);
1084 }
1085
1086 static error_t
install_bootloader(void)1087 install_bootloader(void)
1088 {
1089 nvlist_t *nvl;
1090 uint16_t flags = 0;
1091 int found = 0;
1092 struct extmnttab mnt;
1093 struct stat statbuf = {0};
1094 be_node_list_t *be_nodes, *node;
1095 FILE *fp;
1096 char *root_ds = NULL;
1097 int ret = BAM_ERROR;
1098
1099 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
1100 bam_error(_("out of memory\n"));
1101 return (ret);
1102 }
1103
1104 /*
1105 * if bam_alt_root is set, the stage files are used from alt root.
1106 * if pool is set, the target devices are pool devices, stage files
1107 * are read from pool bootfs unless alt root is set.
1108 *
1109 * use arguments as targets, stage files are from alt or current root
1110 * if no arguments and no pool, install on current boot pool.
1111 */
1112
1113 if (bam_alt_root) {
1114 if (stat(bam_root, &statbuf) != 0) {
1115 bam_error(_("stat of file failed: %s: %s\n"), bam_root,
1116 strerror(errno));
1117 goto done;
1118 }
1119 if ((fp = fopen(MNTTAB, "r")) == NULL) {
1120 bam_error(_("failed to open file: %s: %s\n"),
1121 MNTTAB, strerror(errno));
1122 goto done;
1123 }
1124 resetmnttab(fp);
1125 while (getextmntent(fp, &mnt, sizeof (mnt)) == 0) {
1126 if (mnt.mnt_major == major(statbuf.st_dev) &&
1127 mnt.mnt_minor == minor(statbuf.st_dev)) {
1128 found = 1;
1129 root_ds = strdup(mnt.mnt_special);
1130 break;
1131 }
1132 }
1133 (void) fclose(fp);
1134
1135 if (found == 0) {
1136 bam_error(_("alternate root %s not in mnttab\n"),
1137 bam_root);
1138 goto done;
1139 }
1140 if (root_ds == NULL) {
1141 bam_error(_("out of memory\n"));
1142 goto done;
1143 }
1144
1145 if (be_list(NULL, &be_nodes, BE_LIST_DEFAULT) != BE_SUCCESS) {
1146 bam_error(_("No BE's found\n"));
1147 goto done;
1148 }
1149 for (node = be_nodes; node != NULL; node = node->be_next_node)
1150 if (strcmp(root_ds, node->be_root_ds) == 0)
1151 break;
1152
1153 if (node == NULL)
1154 bam_error(_("BE (%s) does not exist\n"), root_ds);
1155
1156 free(root_ds);
1157 root_ds = NULL;
1158 if (node == NULL) {
1159 be_free_list(be_nodes);
1160 goto done;
1161 }
1162 ret = nvlist_add_string(nvl, BE_ATTR_ORIG_BE_NAME,
1163 node->be_node_name);
1164 ret |= nvlist_add_string(nvl, BE_ATTR_ORIG_BE_ROOT,
1165 node->be_root_ds);
1166 be_free_list(be_nodes);
1167 if (ret != 0) {
1168 ret = BAM_ERROR;
1169 goto done;
1170 }
1171 }
1172
1173 if (bam_force)
1174 flags |= BE_INSTALLBOOT_FLAG_FORCE;
1175 if (bam_mbr)
1176 flags |= BE_INSTALLBOOT_FLAG_MBR;
1177 if (bam_verbose)
1178 flags |= BE_INSTALLBOOT_FLAG_VERBOSE;
1179
1180 if (nvlist_add_uint16(nvl, BE_ATTR_INSTALL_FLAGS, flags) != 0) {
1181 bam_error(_("out of memory\n"));
1182 ret = BAM_ERROR;
1183 goto done;
1184 }
1185
1186 /*
1187 * if altroot was set, we got be name and be root, only need
1188 * to set pool name as target.
1189 * if no altroot, need to find be name and root from pool.
1190 */
1191 if (bam_pool != NULL) {
1192 ret = nvlist_add_string(nvl, BE_ATTR_ORIG_BE_POOL, bam_pool);
1193 if (ret != 0) {
1194 ret = BAM_ERROR;
1195 goto done;
1196 }
1197 if (found) {
1198 ret = be_installboot(nvl);
1199 if (ret != 0)
1200 ret = BAM_ERROR;
1201 goto done;
1202 }
1203 }
1204
1205 if (be_list(NULL, &be_nodes, BE_LIST_DEFAULT) != BE_SUCCESS) {
1206 bam_error(_("No BE's found\n"));
1207 ret = BAM_ERROR;
1208 goto done;
1209 }
1210
1211 if (bam_pool != NULL) {
1212 /*
1213 * find active be_node in bam_pool
1214 */
1215 for (node = be_nodes; node != NULL; node = node->be_next_node) {
1216 if (strcmp(bam_pool, node->be_rpool) != 0)
1217 continue;
1218 if (node->be_active_on_boot)
1219 break;
1220 }
1221 if (node == NULL) {
1222 bam_error(_("No active BE in %s\n"), bam_pool);
1223 be_free_list(be_nodes);
1224 ret = BAM_ERROR;
1225 goto done;
1226 }
1227 ret = nvlist_add_string(nvl, BE_ATTR_ORIG_BE_NAME,
1228 node->be_node_name);
1229 ret |= nvlist_add_string(nvl, BE_ATTR_ORIG_BE_ROOT,
1230 node->be_root_ds);
1231 be_free_list(be_nodes);
1232 if (ret != 0) {
1233 ret = BAM_ERROR;
1234 goto done;
1235 }
1236 ret = be_installboot(nvl);
1237 if (ret != 0)
1238 ret = BAM_ERROR;
1239 goto done;
1240 }
1241
1242 /*
1243 * get dataset for "/" and fill up the args.
1244 */
1245 if ((fp = fopen(MNTTAB, "r")) == NULL) {
1246 bam_error(_("failed to open file: %s: %s\n"),
1247 MNTTAB, strerror(errno));
1248 ret = BAM_ERROR;
1249 be_free_list(be_nodes);
1250 goto done;
1251 }
1252 resetmnttab(fp);
1253 found = 0;
1254 while (getextmntent(fp, &mnt, sizeof (mnt)) == 0) {
1255 if (strcmp(mnt.mnt_mountp, "/") == 0) {
1256 found = 1;
1257 root_ds = strdup(mnt.mnt_special);
1258 break;
1259 }
1260 }
1261 (void) fclose(fp);
1262
1263 if (found == 0) {
1264 bam_error(_("alternate root %s not in mnttab\n"), "/");
1265 ret = BAM_ERROR;
1266 be_free_list(be_nodes);
1267 goto done;
1268 }
1269 if (root_ds == NULL) {
1270 bam_error(_("out of memory\n"));
1271 ret = BAM_ERROR;
1272 be_free_list(be_nodes);
1273 goto done;
1274 }
1275
1276 for (node = be_nodes; node != NULL; node = node->be_next_node) {
1277 if (strcmp(root_ds, node->be_root_ds) == 0)
1278 break;
1279 }
1280
1281 if (node == NULL) {
1282 bam_error(_("No such BE: %s\n"), root_ds);
1283 free(root_ds);
1284 be_free_list(be_nodes);
1285 ret = BAM_ERROR;
1286 goto done;
1287 }
1288 free(root_ds);
1289
1290 ret = nvlist_add_string(nvl, BE_ATTR_ORIG_BE_NAME, node->be_node_name);
1291 ret |= nvlist_add_string(nvl, BE_ATTR_ORIG_BE_ROOT, node->be_root_ds);
1292 ret |= nvlist_add_string(nvl, BE_ATTR_ORIG_BE_POOL, node->be_rpool);
1293 be_free_list(be_nodes);
1294
1295 if (ret != 0)
1296 ret = BAM_ERROR;
1297 else
1298 ret = be_installboot(nvl) ? BAM_ERROR : 0;
1299 done:
1300 nvlist_free(nvl);
1301
1302 return (ret);
1303 }
1304
1305 static error_t
bam_install(char * subcmd,char * opt)1306 bam_install(char *subcmd, char *opt)
1307 {
1308 error_t (*f)(void);
1309
1310 /*
1311 * Check arguments
1312 */
1313 if (check_subcmd_and_options(subcmd, opt, inst_subcmds, &f) ==
1314 BAM_ERROR)
1315 return (BAM_ERROR);
1316
1317 return (f());
1318 }
1319
1320 static error_t
bam_menu(char * subcmd,char * opt,int largc,char * largv[])1321 bam_menu(char *subcmd, char *opt, int largc, char *largv[])
1322 {
1323 error_t ret;
1324 char menu_path[PATH_MAX];
1325 char clean_menu_root[PATH_MAX];
1326 char path[PATH_MAX];
1327 menu_t *menu;
1328 char menu_root[PATH_MAX];
1329 struct stat sb;
1330 error_t (*f)(menu_t *mp, char *menu_path, char *opt);
1331 char *special = NULL;
1332 char *pool = NULL;
1333 zfs_mnted_t zmnted;
1334 char *zmntpt = NULL;
1335 char *osdev;
1336 char *osroot;
1337 const char *fcn = "bam_menu()";
1338
1339 /*
1340 * Menu sub-command only applies to GRUB (i.e. x86)
1341 */
1342 if (!is_grub(bam_alt_root ? bam_root : "/")) {
1343 bam_error(_("not a GRUB 0.97 based Illumos instance. "
1344 "Operation not supported\n"));
1345 return (BAM_ERROR);
1346 }
1347
1348 /*
1349 * Check arguments
1350 */
1351 ret = check_subcmd_and_options(subcmd, opt, menu_subcmds, &f);
1352 if (ret == BAM_ERROR) {
1353 return (BAM_ERROR);
1354 }
1355
1356 assert(bam_root);
1357
1358 (void) strlcpy(menu_root, bam_root, sizeof (menu_root));
1359 osdev = osroot = NULL;
1360
1361 if (strcmp(subcmd, "update_entry") == 0) {
1362 assert(opt);
1363
1364 osdev = strtok(opt, ",");
1365 assert(osdev);
1366 osroot = strtok(NULL, ",");
1367 if (osroot) {
1368 /* fixup bam_root so that it points at osroot */
1369 if (realpath(osroot, rootbuf) == NULL) {
1370 bam_error(_("cannot resolve path %s: %s\n"),
1371 osroot, strerror(errno));
1372 return (BAM_ERROR);
1373 }
1374 bam_alt_root = 1;
1375 bam_root = rootbuf;
1376 bam_rootlen = strlen(rootbuf);
1377 }
1378 }
1379
1380 /*
1381 * We support menu on PCFS (under certain conditions), but
1382 * not the OS root
1383 */
1384 if (is_pcfs(bam_root)) {
1385 bam_error(_("root <%s> on PCFS is not supported\n"), bam_root);
1386 return (BAM_ERROR);
1387 }
1388
1389 if (stat(menu_root, &sb) == -1) {
1390 bam_error(_("cannot find GRUB menu\n"));
1391 return (BAM_ERROR);
1392 }
1393
1394 BAM_DPRINTF(("%s: menu root is %s\n", fcn, menu_root));
1395
1396 /*
1397 * We no longer use the GRUB slice file. If it exists, then
1398 * the user is doing something that is unsupported (such as
1399 * standard upgrading an old Live Upgrade BE). If that
1400 * happens, mimic existing behavior i.e. pretend that it is
1401 * not a BE. Emit a warning though.
1402 */
1403 if (bam_alt_root) {
1404 (void) snprintf(path, sizeof (path), "%s%s", bam_root,
1405 GRUB_slice);
1406 } else {
1407 (void) snprintf(path, sizeof (path), "%s", GRUB_slice);
1408 }
1409
1410 if (bam_verbose && stat(path, &sb) == 0)
1411 bam_error(_("unsupported GRUB slice file (%s) exists - "
1412 "ignoring.\n"), path);
1413
1414 if (is_zfs(menu_root)) {
1415 assert(strcmp(menu_root, bam_root) == 0);
1416 special = get_special(menu_root);
1417 INJECT_ERROR1("Z_MENU_GET_SPECIAL", special = NULL);
1418 if (special == NULL) {
1419 bam_error(_("cant find special file for "
1420 "mount-point %s\n"), menu_root);
1421 return (BAM_ERROR);
1422 }
1423 pool = strtok(special, "/");
1424 INJECT_ERROR1("Z_MENU_GET_POOL", pool = NULL);
1425 if (pool == NULL) {
1426 free(special);
1427 bam_error(_("cant find pool for mount-point %s\n"),
1428 menu_root);
1429 return (BAM_ERROR);
1430 }
1431 BAM_DPRINTF(("%s: derived pool=%s from special\n", fcn, pool));
1432
1433 zmntpt = mount_top_dataset(pool, &zmnted);
1434 INJECT_ERROR1("Z_MENU_MOUNT_TOP_DATASET", zmntpt = NULL);
1435 if (zmntpt == NULL) {
1436 bam_error(_("cannot mount pool dataset for pool: %s\n"),
1437 pool);
1438 free(special);
1439 return (BAM_ERROR);
1440 }
1441 BAM_DPRINTF(("%s: top dataset mountpoint=%s\n", fcn, zmntpt));
1442
1443 (void) strlcpy(menu_root, zmntpt, sizeof (menu_root));
1444 BAM_DPRINTF(("%s: zfs menu_root=%s\n", fcn, menu_root));
1445 }
1446
1447 elide_trailing_slash(menu_root, clean_menu_root,
1448 sizeof (clean_menu_root));
1449
1450 BAM_DPRINTF(("%s: cleaned menu root is <%s>\n", fcn, clean_menu_root));
1451
1452 (void) strlcpy(menu_path, clean_menu_root, sizeof (menu_path));
1453 (void) strlcat(menu_path, GRUB_MENU, sizeof (menu_path));
1454
1455 BAM_DPRINTF(("%s: menu path is: %s\n", fcn, menu_path));
1456
1457 /*
1458 * If listing the menu, display the menu location
1459 */
1460 if (strcmp(subcmd, "list_entry") == 0)
1461 bam_print(_("the location for the active GRUB menu is: %s\n"),
1462 menu_path);
1463
1464 if ((menu = menu_read(menu_path)) == NULL) {
1465 bam_error(_("cannot find GRUB menu file: %s\n"), menu_path);
1466 free(special);
1467
1468 return (BAM_ERROR);
1469 }
1470
1471 /*
1472 * We already checked the following case in
1473 * check_subcmd_and_suboptions() above. Complete the
1474 * final step now.
1475 */
1476 if (strcmp(subcmd, "set_option") == 0) {
1477 assert(largc == 1 && largv[0] && largv[1] == NULL);
1478 opt = largv[0];
1479 } else if ((strcmp(subcmd, "enable_hypervisor") != 0) &&
1480 (strcmp(subcmd, "list_setting") != 0)) {
1481 assert(largc == 0 && largv == NULL);
1482 }
1483
1484 ret = get_boot_cap(bam_root);
1485 if (ret != BAM_SUCCESS) {
1486 BAM_DPRINTF(("%s: Failed to get boot capability\n", fcn));
1487 goto out;
1488 }
1489
1490 /*
1491 * Once the sub-cmd handler has run
1492 * only the line field is guaranteed to have valid values
1493 */
1494 if (strcmp(subcmd, "update_entry") == 0) {
1495 ret = f(menu, menu_root, osdev);
1496 } else if (strcmp(subcmd, "upgrade") == 0) {
1497 ret = f(menu, bam_root, menu_root);
1498 } else if (strcmp(subcmd, "list_entry") == 0) {
1499 ret = f(menu, menu_path, opt);
1500 } else if (strcmp(subcmd, "list_setting") == 0) {
1501 ret = f(menu, ((largc > 0) ? largv[0] : ""),
1502 ((largc > 1) ? largv[1] : ""));
1503 } else if (strcmp(subcmd, "disable_hypervisor") == 0) {
1504 if (is_sparc()) {
1505 bam_error(_("%s operation unsupported on SPARC "
1506 "machines\n"), subcmd);
1507 ret = BAM_ERROR;
1508 } else {
1509 ret = f(menu, bam_root, NULL);
1510 }
1511 } else if (strcmp(subcmd, "enable_hypervisor") == 0) {
1512 if (is_sparc()) {
1513 bam_error(_("%s operation unsupported on SPARC "
1514 "machines\n"), subcmd);
1515 ret = BAM_ERROR;
1516 } else {
1517 char *extra_args = NULL;
1518
1519 /*
1520 * Compress all arguments passed in the largv[] array
1521 * into one string that can then be appended to the
1522 * end of the kernel$ string the routine to enable the
1523 * hypervisor will build.
1524 *
1525 * This allows the caller to supply arbitrary unparsed
1526 * arguments, such as dom0 memory settings or APIC
1527 * options.
1528 *
1529 * This concatenation will be done without ANY syntax
1530 * checking whatsoever, so it's the responsibility of
1531 * the caller to make sure the arguments are valid and
1532 * do not duplicate arguments the conversion routines
1533 * may create.
1534 */
1535 if (largc > 0) {
1536 int extra_len, i;
1537
1538 for (extra_len = 0, i = 0; i < largc; i++)
1539 extra_len += strlen(largv[i]);
1540
1541 /*
1542 * Allocate space for argument strings,
1543 * intervening spaces and terminating NULL.
1544 */
1545 extra_args = alloca(extra_len + largc);
1546
1547 (void) strcpy(extra_args, largv[0]);
1548
1549 for (i = 1; i < largc; i++) {
1550 (void) strcat(extra_args, " ");
1551 (void) strcat(extra_args, largv[i]);
1552 }
1553 }
1554
1555 ret = f(menu, bam_root, extra_args);
1556 }
1557 } else
1558 ret = f(menu, NULL, opt);
1559
1560 if (ret == BAM_WRITE) {
1561 BAM_DPRINTF(("%s: writing menu to clean-menu-root: <%s>\n",
1562 fcn, clean_menu_root));
1563 ret = menu_write(clean_menu_root, menu);
1564 }
1565
1566 out:
1567 INJECT_ERROR1("POOL_SET", pool = "/pooldata");
1568 assert((is_zfs(menu_root)) ^ (pool == NULL));
1569 if (pool) {
1570 (void) umount_top_dataset(pool, zmnted, zmntpt);
1571 free(special);
1572 }
1573 menu_free(menu);
1574 return (ret);
1575 }
1576
1577
1578 static error_t
bam_archive(char * subcmd,char * opt)1579 bam_archive(
1580 char *subcmd,
1581 char *opt)
1582 {
1583 error_t ret;
1584 error_t (*f)(char *root, char *opt);
1585 const char *fcn = "bam_archive()";
1586
1587 /*
1588 * Add trailing / for archive subcommands
1589 */
1590 if (rootbuf[strlen(rootbuf) - 1] != '/')
1591 (void) strcat(rootbuf, "/");
1592 bam_rootlen = strlen(rootbuf);
1593
1594 /*
1595 * Check arguments
1596 */
1597 ret = check_subcmd_and_options(subcmd, opt, arch_subcmds, &f);
1598 if (ret != BAM_SUCCESS) {
1599 return (BAM_ERROR);
1600 }
1601
1602 ret = get_boot_cap(rootbuf);
1603 if (ret != BAM_SUCCESS) {
1604 BAM_DPRINTF(("%s: Failed to get boot capability\n", fcn));
1605 return (ret);
1606 }
1607
1608 /*
1609 * Check archive not supported with update_all
1610 * since it is awkward to display out-of-sync
1611 * information for each BE.
1612 */
1613 if (bam_check && strcmp(subcmd, "update_all") == 0) {
1614 bam_error(_("the check option is not supported with "
1615 "subcmd: %s\n"), subcmd);
1616 return (BAM_ERROR);
1617 }
1618
1619 if (strcmp(subcmd, "update_all") == 0)
1620 bam_update_all = 1;
1621
1622 #if !defined(_OBP)
1623 ucode_install(bam_root);
1624 #endif
1625
1626 ret = f(bam_root, opt);
1627
1628 bam_update_all = 0;
1629
1630 return (ret);
1631 }
1632
1633 /*PRINTFLIKE1*/
1634 void
bam_error(char * format,...)1635 bam_error(char *format, ...)
1636 {
1637 va_list ap;
1638
1639 va_start(ap, format);
1640 (void) fprintf(stderr, "%s: ", prog);
1641 (void) vfprintf(stderr, format, ap);
1642 va_end(ap);
1643 }
1644
1645 /*PRINTFLIKE1*/
1646 void
bam_derror(char * format,...)1647 bam_derror(char *format, ...)
1648 {
1649 va_list ap;
1650
1651 assert(bam_debug);
1652
1653 va_start(ap, format);
1654 (void) fprintf(stderr, "DEBUG: ");
1655 (void) vfprintf(stderr, format, ap);
1656 va_end(ap);
1657 }
1658
1659 /*PRINTFLIKE1*/
1660 void
bam_print(char * format,...)1661 bam_print(char *format, ...)
1662 {
1663 va_list ap;
1664
1665 va_start(ap, format);
1666 (void) vfprintf(stdout, format, ap);
1667 va_end(ap);
1668 }
1669
1670 /*PRINTFLIKE1*/
1671 void
bam_print_stderr(char * format,...)1672 bam_print_stderr(char *format, ...)
1673 {
1674 va_list ap;
1675
1676 va_start(ap, format);
1677 (void) vfprintf(stderr, format, ap);
1678 va_end(ap);
1679 }
1680
1681 void
bam_exit(int excode)1682 bam_exit(int excode)
1683 {
1684 restore_env();
1685 bam_unlock();
1686 exit(excode);
1687 }
1688
1689 static void
bam_lock(void)1690 bam_lock(void)
1691 {
1692 struct flock lock;
1693 pid_t pid;
1694
1695 if (bam_skip_lock)
1696 return;
1697
1698 bam_lock_fd = open(BAM_LOCK_FILE, O_CREAT|O_RDWR, LOCK_FILE_PERMS);
1699 if (bam_lock_fd < 0) {
1700 /*
1701 * We may be invoked early in boot for archive verification.
1702 * In this case, root is readonly and /var/run may not exist.
1703 * Proceed without the lock
1704 */
1705 if (errno == EROFS || errno == ENOENT) {
1706 bam_root_readonly = 1;
1707 return;
1708 }
1709
1710 bam_error(_("failed to open file: %s: %s\n"),
1711 BAM_LOCK_FILE, strerror(errno));
1712 bam_exit(1);
1713 }
1714
1715 lock.l_type = F_WRLCK;
1716 lock.l_whence = SEEK_SET;
1717 lock.l_start = 0;
1718 lock.l_len = 0;
1719
1720 if (fcntl(bam_lock_fd, F_SETLK, &lock) == -1) {
1721 if (errno != EACCES && errno != EAGAIN) {
1722 bam_error(_("failed to lock file: %s: %s\n"),
1723 BAM_LOCK_FILE, strerror(errno));
1724 (void) close(bam_lock_fd);
1725 bam_lock_fd = -1;
1726 bam_exit(1);
1727 }
1728 pid = 0;
1729 (void) pread(bam_lock_fd, &pid, sizeof (pid_t), 0);
1730 bam_print(
1731 _("another instance of bootadm (pid %lu) is running\n"),
1732 pid);
1733
1734 lock.l_type = F_WRLCK;
1735 lock.l_whence = SEEK_SET;
1736 lock.l_start = 0;
1737 lock.l_len = 0;
1738 if (fcntl(bam_lock_fd, F_SETLKW, &lock) == -1) {
1739 bam_error(_("failed to lock file: %s: %s\n"),
1740 BAM_LOCK_FILE, strerror(errno));
1741 (void) close(bam_lock_fd);
1742 bam_lock_fd = -1;
1743 bam_exit(1);
1744 }
1745 }
1746
1747 /* We own the lock now */
1748 pid = getpid();
1749 (void) write(bam_lock_fd, &pid, sizeof (pid));
1750 }
1751
1752 static void
bam_unlock(void)1753 bam_unlock(void)
1754 {
1755 struct flock unlock;
1756
1757 if (bam_skip_lock)
1758 return;
1759
1760 /*
1761 * NOP if we don't hold the lock
1762 */
1763 if (bam_lock_fd < 0) {
1764 return;
1765 }
1766
1767 unlock.l_type = F_UNLCK;
1768 unlock.l_whence = SEEK_SET;
1769 unlock.l_start = 0;
1770 unlock.l_len = 0;
1771
1772 if (fcntl(bam_lock_fd, F_SETLK, &unlock) == -1) {
1773 bam_error(_("failed to unlock file: %s: %s\n"),
1774 BAM_LOCK_FILE, strerror(errno));
1775 }
1776
1777 if (close(bam_lock_fd) == -1) {
1778 bam_error(_("failed to close file: %s: %s\n"),
1779 BAM_LOCK_FILE, strerror(errno));
1780 }
1781 bam_lock_fd = -1;
1782 }
1783
1784 static error_t
list_archive(char * root,char * opt)1785 list_archive(char *root, char *opt)
1786 {
1787 filelist_t flist;
1788 filelist_t *flistp = &flist;
1789 line_t *lp;
1790
1791 assert(root);
1792 assert(opt == NULL);
1793
1794 flistp->head = flistp->tail = NULL;
1795 if (read_list(root, flistp) != BAM_SUCCESS) {
1796 return (BAM_ERROR);
1797 }
1798 assert(flistp->head && flistp->tail);
1799
1800 for (lp = flistp->head; lp; lp = lp->next) {
1801 bam_print(_("%s\n"), lp->line);
1802 }
1803
1804 filelist_free(flistp);
1805
1806 return (BAM_SUCCESS);
1807 }
1808
1809 /*
1810 * This routine writes a list of lines to a file.
1811 * The list is *not* freed
1812 */
1813 static error_t
list2file(char * root,char * tmp,char * final,line_t * start)1814 list2file(char *root, char *tmp, char *final, line_t *start)
1815 {
1816 char tmpfile[PATH_MAX];
1817 char path[PATH_MAX];
1818 FILE *fp;
1819 int ret;
1820 struct stat sb;
1821 mode_t mode;
1822 uid_t root_uid;
1823 gid_t sys_gid;
1824 struct passwd *pw;
1825 struct group *gp;
1826 const char *fcn = "list2file()";
1827
1828 (void) snprintf(path, sizeof (path), "%s%s", root, final);
1829
1830 if (start == NULL) {
1831 /* Empty GRUB menu */
1832 if (stat(path, &sb) != -1) {
1833 bam_print(_("file is empty, deleting file: %s\n"),
1834 path);
1835 if (unlink(path) != 0) {
1836 bam_error(_("failed to unlink file: %s: %s\n"),
1837 path, strerror(errno));
1838 return (BAM_ERROR);
1839 } else {
1840 return (BAM_SUCCESS);
1841 }
1842 }
1843 return (BAM_SUCCESS);
1844 }
1845
1846 /*
1847 * Preserve attributes of existing file if possible,
1848 * otherwise ask the system for uid/gid of root/sys.
1849 * If all fails, fall back on hard-coded defaults.
1850 */
1851 if (stat(path, &sb) != -1) {
1852 mode = sb.st_mode;
1853 root_uid = sb.st_uid;
1854 sys_gid = sb.st_gid;
1855 } else {
1856 mode = DEFAULT_DEV_MODE;
1857 if ((pw = getpwnam(DEFAULT_DEV_USER)) != NULL) {
1858 root_uid = pw->pw_uid;
1859 } else {
1860 bam_error(_("getpwnam: uid for %s failed, "
1861 "defaulting to %d\n"),
1862 DEFAULT_DEV_USER, DEFAULT_DEV_UID);
1863 root_uid = (uid_t)DEFAULT_DEV_UID;
1864 }
1865 if ((gp = getgrnam(DEFAULT_DEV_GROUP)) != NULL) {
1866 sys_gid = gp->gr_gid;
1867 } else {
1868 bam_error(_("getgrnam: gid for %s failed, "
1869 "defaulting to %d\n"),
1870 DEFAULT_DEV_GROUP, DEFAULT_DEV_GID);
1871 sys_gid = (gid_t)DEFAULT_DEV_GID;
1872 }
1873 }
1874
1875 (void) snprintf(tmpfile, sizeof (tmpfile), "%s%s", root, tmp);
1876
1877 /* Truncate tmpfile first */
1878 fp = fopen(tmpfile, "w");
1879 if (fp == NULL) {
1880 bam_error(_("failed to open file: %s: %s\n"), tmpfile,
1881 strerror(errno));
1882 return (BAM_ERROR);
1883 }
1884 ret = fclose(fp);
1885 INJECT_ERROR1("LIST2FILE_TRUNC_FCLOSE", ret = EOF);
1886 if (ret == EOF) {
1887 bam_error(_("failed to close file: %s: %s\n"),
1888 tmpfile, strerror(errno));
1889 return (BAM_ERROR);
1890 }
1891
1892 /* Now open it in append mode */
1893 fp = fopen(tmpfile, "a");
1894 if (fp == NULL) {
1895 bam_error(_("failed to open file: %s: %s\n"), tmpfile,
1896 strerror(errno));
1897 return (BAM_ERROR);
1898 }
1899
1900 for (; start; start = start->next) {
1901 ret = s_fputs(start->line, fp);
1902 INJECT_ERROR1("LIST2FILE_FPUTS", ret = EOF);
1903 if (ret == EOF) {
1904 bam_error(_("write to file failed: %s: %s\n"),
1905 tmpfile, strerror(errno));
1906 (void) fclose(fp);
1907 return (BAM_ERROR);
1908 }
1909 }
1910
1911 ret = fclose(fp);
1912 INJECT_ERROR1("LIST2FILE_APPEND_FCLOSE", ret = EOF);
1913 if (ret == EOF) {
1914 bam_error(_("failed to close file: %s: %s\n"),
1915 tmpfile, strerror(errno));
1916 return (BAM_ERROR);
1917 }
1918
1919 /*
1920 * Set up desired attributes. Ignore failures on filesystems
1921 * not supporting these operations - pcfs reports unsupported
1922 * operations as EINVAL.
1923 */
1924 ret = chmod(tmpfile, mode);
1925 if (ret == -1 &&
1926 errno != EINVAL && errno != ENOTSUP) {
1927 bam_error(_("chmod operation on %s failed - %s\n"),
1928 tmpfile, strerror(errno));
1929 return (BAM_ERROR);
1930 }
1931
1932 ret = chown(tmpfile, root_uid, sys_gid);
1933 if (ret == -1 &&
1934 errno != EINVAL && errno != ENOTSUP) {
1935 bam_error(_("chgrp operation on %s failed - %s\n"),
1936 tmpfile, strerror(errno));
1937 return (BAM_ERROR);
1938 }
1939
1940 /*
1941 * Do an atomic rename
1942 */
1943 ret = rename(tmpfile, path);
1944 INJECT_ERROR1("LIST2FILE_RENAME", ret = -1);
1945 if (ret != 0) {
1946 bam_error(_("rename to file failed: %s: %s\n"), path,
1947 strerror(errno));
1948 return (BAM_ERROR);
1949 }
1950
1951 BAM_DPRINTF(("%s: wrote file successfully: %s\n", fcn, path));
1952 return (BAM_SUCCESS);
1953 }
1954
1955 /*
1956 * Checks if the path specified (without the file name at the end) exists
1957 * and creates it if not. If the path exists and is not a directory, an attempt
1958 * to unlink is made.
1959 */
1960 static int
setup_path(char * path)1961 setup_path(char *path)
1962 {
1963 char *p;
1964 int ret;
1965 struct stat sb;
1966
1967 p = strrchr(path, '/');
1968 if (p != NULL) {
1969 *p = '\0';
1970 if (stat(path, &sb) != 0 || !(S_ISDIR(sb.st_mode))) {
1971 /* best effort attempt, mkdirp will catch the error */
1972 (void) unlink(path);
1973 if (bam_verbose)
1974 bam_print(_("need to create directory "
1975 "path for %s\n"), path);
1976 ret = mkdirp(path, DIR_PERMS);
1977 if (ret == -1) {
1978 bam_error(_("mkdir of %s failed: %s\n"),
1979 path, strerror(errno));
1980 *p = '/';
1981 return (BAM_ERROR);
1982 }
1983 }
1984 *p = '/';
1985 return (BAM_SUCCESS);
1986 }
1987 return (BAM_SUCCESS);
1988 }
1989
1990 typedef union {
1991 gzFile gzfile;
1992 int fdfile;
1993 } outfile;
1994
1995 typedef struct {
1996 char path[PATH_MAX];
1997 outfile out;
1998 } cachefile;
1999
2000 static int
setup_file(char * base,const char * path,cachefile * cf)2001 setup_file(char *base, const char *path, cachefile *cf)
2002 {
2003 int ret;
2004 char *strip;
2005
2006 /* init gzfile or fdfile in case we fail before opening */
2007 if (bam_direct == BAM_DIRECT_DBOOT)
2008 cf->out.gzfile = NULL;
2009 else
2010 cf->out.fdfile = -1;
2011
2012 /* strip the trailing altroot path */
2013 strip = (char *)path + strlen(rootbuf);
2014
2015 ret = snprintf(cf->path, sizeof (cf->path), "%s/%s", base, strip);
2016 if (ret >= sizeof (cf->path)) {
2017 bam_error(_("unable to create path on mountpoint %s, "
2018 "path too long\n"), rootbuf);
2019 return (BAM_ERROR);
2020 }
2021
2022 /* Check if path is present in the archive cache directory */
2023 if (setup_path(cf->path) == BAM_ERROR)
2024 return (BAM_ERROR);
2025
2026 if (bam_direct == BAM_DIRECT_DBOOT) {
2027 if ((cf->out.gzfile = gzopen(cf->path, "wb")) == NULL) {
2028 bam_error(_("failed to open file: %s: %s\n"),
2029 cf->path, strerror(errno));
2030 return (BAM_ERROR);
2031 }
2032 (void) gzsetparams(cf->out.gzfile, Z_BEST_SPEED,
2033 Z_DEFAULT_STRATEGY);
2034 } else {
2035 if ((cf->out.fdfile = open(cf->path, O_WRONLY | O_CREAT, 0644))
2036 == -1) {
2037 bam_error(_("failed to open file: %s: %s\n"),
2038 cf->path, strerror(errno));
2039 return (BAM_ERROR);
2040 }
2041 }
2042
2043 return (BAM_SUCCESS);
2044 }
2045
2046 static int
cache_write(cachefile cf,char * buf,int size)2047 cache_write(cachefile cf, char *buf, int size)
2048 {
2049 int err;
2050
2051 if (bam_direct == BAM_DIRECT_DBOOT) {
2052 if (gzwrite(cf.out.gzfile, buf, size) < 1) {
2053 bam_error(_("failed to write to %s\n"),
2054 gzerror(cf.out.gzfile, &err));
2055 if (err == Z_ERRNO && bam_verbose) {
2056 bam_error(_("write to file failed: %s: %s\n"),
2057 cf.path, strerror(errno));
2058 }
2059 return (BAM_ERROR);
2060 }
2061 } else {
2062 if (write(cf.out.fdfile, buf, size) < 1) {
2063 bam_error(_("write to file failed: %s: %s\n"),
2064 cf.path, strerror(errno));
2065 return (BAM_ERROR);
2066 }
2067 }
2068 return (BAM_SUCCESS);
2069 }
2070
2071 static int
cache_close(cachefile cf)2072 cache_close(cachefile cf)
2073 {
2074 int ret;
2075
2076 if (bam_direct == BAM_DIRECT_DBOOT) {
2077 if (cf.out.gzfile) {
2078 ret = gzclose(cf.out.gzfile);
2079 if (ret != Z_OK) {
2080 bam_error(_("failed to close file: %s: %s\n"),
2081 cf.path, strerror(errno));
2082 return (BAM_ERROR);
2083 }
2084 }
2085 } else {
2086 if (cf.out.fdfile != -1) {
2087 ret = close(cf.out.fdfile);
2088 if (ret != 0) {
2089 bam_error(_("failed to close file: %s: %s\n"),
2090 cf.path, strerror(errno));
2091 return (BAM_ERROR);
2092 }
2093 }
2094 }
2095
2096 return (BAM_SUCCESS);
2097 }
2098
2099 static int
dircache_updatefile(const char * path)2100 dircache_updatefile(const char *path)
2101 {
2102 int ret, exitcode;
2103 char buf[4096 * 4];
2104 FILE *infile;
2105 cachefile outfile, outupdt;
2106
2107 if (bam_nowrite()) {
2108 set_dir_flag(NEED_UPDATE);
2109 return (BAM_SUCCESS);
2110 }
2111
2112 if (!has_cachedir())
2113 return (BAM_SUCCESS);
2114
2115 if ((infile = fopen(path, "rb")) == NULL) {
2116 bam_error(_("failed to open file: %s: %s\n"), path,
2117 strerror(errno));
2118 return (BAM_ERROR);
2119 }
2120
2121 ret = setup_file(get_cachedir(), path, &outfile);
2122 if (ret == BAM_ERROR) {
2123 exitcode = BAM_ERROR;
2124 goto out;
2125 }
2126 if (!is_dir_flag_on(NO_EXTEND)) {
2127 ret = setup_file(get_updatedir(), path, &outupdt);
2128 if (ret == BAM_ERROR)
2129 set_dir_flag(NO_EXTEND);
2130 }
2131
2132 while ((ret = fread(buf, 1, sizeof (buf), infile)) > 0) {
2133 if (cache_write(outfile, buf, ret) == BAM_ERROR) {
2134 exitcode = BAM_ERROR;
2135 goto out;
2136 }
2137 if (!is_dir_flag_on(NO_EXTEND))
2138 if (cache_write(outupdt, buf, ret) == BAM_ERROR)
2139 set_dir_flag(NO_EXTEND);
2140 }
2141
2142 set_dir_flag(NEED_UPDATE);
2143 get_count()++;
2144 if (get_count() > COUNT_MAX)
2145 set_dir_flag(NO_EXTEND);
2146 exitcode = BAM_SUCCESS;
2147 out:
2148 (void) fclose(infile);
2149 if (cache_close(outfile) == BAM_ERROR)
2150 exitcode = BAM_ERROR;
2151 if (!is_dir_flag_on(NO_EXTEND) &&
2152 cache_close(outupdt) == BAM_ERROR)
2153 exitcode = BAM_ERROR;
2154 if (exitcode == BAM_ERROR)
2155 set_flag(UPDATE_ERROR);
2156 return (exitcode);
2157 }
2158
2159 static int
dircache_updatedir(const char * path,int updt)2160 dircache_updatedir(const char *path, int updt)
2161 {
2162 int ret;
2163 char dpath[PATH_MAX];
2164 char *strip;
2165 struct stat sb;
2166
2167 strip = (char *)path + strlen(rootbuf);
2168
2169 ret = snprintf(dpath, sizeof (dpath), "%s/%s", updt ?
2170 get_updatedir() : get_cachedir(), strip);
2171
2172 if (ret >= sizeof (dpath)) {
2173 bam_error(_("unable to create path on mountpoint %s, "
2174 "path too long\n"), rootbuf);
2175 set_flag(UPDATE_ERROR);
2176 return (BAM_ERROR);
2177 }
2178
2179 if (stat(dpath, &sb) == 0 && S_ISDIR(sb.st_mode))
2180 return (BAM_SUCCESS);
2181
2182 if (updt) {
2183 if (!is_dir_flag_on(NO_EXTEND))
2184 if (!bam_nowrite() && mkdirp(dpath, DIR_PERMS) == -1)
2185 set_dir_flag(NO_EXTEND);
2186 } else {
2187 if (!bam_nowrite() && mkdirp(dpath, DIR_PERMS) == -1) {
2188 set_flag(UPDATE_ERROR);
2189 return (BAM_ERROR);
2190 }
2191 }
2192
2193 set_dir_flag(NEED_UPDATE);
2194 return (BAM_SUCCESS);
2195 }
2196
2197 #define DO_CACHE_DIR 0
2198 #define DO_UPDATE_DIR 1
2199
2200 #if defined(_LP64) || defined(_LONGLONG_TYPE)
2201 typedef Elf64_Ehdr _elfhdr;
2202 #else
2203 typedef Elf32_Ehdr _elfhdr;
2204 #endif
2205
2206 /*
2207 * This routine updates the contents of the cache directory
2208 */
2209 static int
update_dircache(const char * path,int flags)2210 update_dircache(const char *path, int flags)
2211 {
2212 int rc = BAM_SUCCESS;
2213
2214 switch (flags) {
2215 case FTW_F:
2216 {
2217 int fd;
2218 _elfhdr elf;
2219
2220 if ((fd = open(path, O_RDONLY)) < 0) {
2221 bam_error(_("failed to open file: %s: %s\n"),
2222 path, strerror(errno));
2223 set_flag(UPDATE_ERROR);
2224 rc = BAM_ERROR;
2225 break;
2226 }
2227
2228 /*
2229 * libelf and gelf would be a cleaner and easier way to handle
2230 * this, but libelf fails compilation if _ILP32 is defined &&
2231 * _FILE_OFFSET_BITS is != 32 ...
2232 */
2233 if (read(fd, (void *)&elf, sizeof (_elfhdr)) < 0) {
2234 bam_error(_("read failed for file: %s: %s\n"),
2235 path, strerror(errno));
2236 set_flag(UPDATE_ERROR);
2237 (void) close(fd);
2238 rc = BAM_ERROR;
2239 break;
2240 }
2241 (void) close(fd);
2242
2243 if (memcmp(elf.e_ident, ELFMAG, 4) != 0) {
2244 /* Not an ELF file, include in archive */
2245 rc = dircache_updatefile(path);
2246 } else {
2247 /* Include 64-bit ELF files only */
2248 switch (elf.e_ident[EI_CLASS]) {
2249 case ELFCLASS32:
2250 bam_print(_("WARNING: ELF file %s is 32-bit "
2251 "and will be excluded\n"), path);
2252 break;
2253 case ELFCLASS64:
2254 rc = dircache_updatefile(path);
2255 break;
2256 default:
2257 bam_print(_("WARNING: ELF file %s is neither "
2258 "32-bit nor 64-bit\n"), path);
2259 break;
2260 }
2261 }
2262 break;
2263 }
2264 case FTW_D:
2265 if (strstr(path, "/amd64") != NULL) {
2266 if (has_cachedir()) {
2267 rc = dircache_updatedir(path, DO_UPDATE_DIR);
2268 if (rc == BAM_SUCCESS)
2269 rc = dircache_updatedir(path,
2270 DO_CACHE_DIR);
2271 }
2272 }
2273 break;
2274 default:
2275 rc = BAM_ERROR;
2276 break;
2277 }
2278
2279 return (rc);
2280 }
2281
2282 /*ARGSUSED*/
2283 static int
cmpstat(const char * file,const struct stat * st,int flags,struct FTW * ftw)2284 cmpstat(
2285 const char *file,
2286 const struct stat *st,
2287 int flags,
2288 struct FTW *ftw)
2289 {
2290 uint_t sz;
2291 uint64_t *value;
2292 uint64_t filestat[2];
2293 int error, ret, status;
2294
2295 struct safefile *safefilep;
2296 FILE *fp;
2297 struct stat sb;
2298 regex_t re;
2299
2300 /*
2301 * On SPARC we create/update links too.
2302 */
2303 if (flags != FTW_F && flags != FTW_D && (flags == FTW_SL &&
2304 !is_flag_on(IS_SPARC_TARGET)))
2305 return (0);
2306
2307 /*
2308 * Ignore broken links
2309 */
2310 if (flags == FTW_SL && stat(file, &sb) < 0)
2311 return (0);
2312
2313 /*
2314 * new_nvlp may be NULL if there were errors earlier
2315 * but this is not fatal to update determination.
2316 */
2317 if (walk_arg.new_nvlp) {
2318 filestat[0] = st->st_size;
2319 filestat[1] = st->st_mtime;
2320 error = nvlist_add_uint64_array(walk_arg.new_nvlp,
2321 file + bam_rootlen, filestat, 2);
2322 if (error)
2323 bam_error(_("failed to update stat data for: %s: %s\n"),
2324 file, strerror(error));
2325 }
2326
2327 /*
2328 * If we are invoked as part of system/filesystem/boot-archive, then
2329 * there are a number of things we should not worry about
2330 */
2331 if (bam_smf_check) {
2332 /* ignore amd64 modules unless we are booted amd64. */
2333 if (!is_amd64() && strstr(file, "/amd64/") != 0)
2334 return (0);
2335
2336 /* read in list of safe files */
2337 if (safefiles == NULL) {
2338 fp = fopen("/boot/solaris/filelist.safe", "r");
2339 if (fp != NULL) {
2340 safefiles = s_calloc(1,
2341 sizeof (struct safefile));
2342 safefilep = safefiles;
2343 safefilep->name = s_calloc(1, MAXPATHLEN +
2344 MAXNAMELEN);
2345 safefilep->next = NULL;
2346 while (s_fgets(safefilep->name, MAXPATHLEN +
2347 MAXNAMELEN, fp) != NULL) {
2348 safefilep->next = s_calloc(1,
2349 sizeof (struct safefile));
2350 safefilep = safefilep->next;
2351 safefilep->name = s_calloc(1,
2352 MAXPATHLEN + MAXNAMELEN);
2353 safefilep->next = NULL;
2354 }
2355 (void) fclose(fp);
2356 }
2357 }
2358 }
2359
2360 /*
2361 * On SPARC we create a -path-list file for mkisofs
2362 */
2363 if (is_flag_on(IS_SPARC_TARGET) && !bam_nowrite()) {
2364 if (flags != FTW_D) {
2365 char *strip;
2366
2367 strip = (char *)file + strlen(rootbuf);
2368 (void) fprintf(walk_arg.sparcfile, "/%s=%s\n", strip,
2369 file);
2370 }
2371 }
2372
2373 /*
2374 * We are transitioning from the old model to the dircache or the cache
2375 * directory was removed: create the entry without further checkings.
2376 */
2377 if (is_flag_on(NEED_CACHE_DIR)) {
2378 if (bam_verbose)
2379 bam_print(_(" new %s\n"), file);
2380
2381 if (is_flag_on(IS_SPARC_TARGET)) {
2382 set_dir_flag(NEED_UPDATE);
2383 return (0);
2384 }
2385
2386 ret = update_dircache(file, flags);
2387 if (ret == BAM_ERROR) {
2388 bam_error(_("directory cache update failed for %s\n"),
2389 file);
2390 return (-1);
2391 }
2392
2393 return (0);
2394 }
2395
2396 /*
2397 * We need an update if file doesn't exist in old archive
2398 */
2399 if (walk_arg.old_nvlp == NULL ||
2400 nvlist_lookup_uint64_array(walk_arg.old_nvlp,
2401 file + bam_rootlen, &value, &sz) != 0) {
2402 if (bam_smf_check) /* ignore new during smf check */
2403 return (0);
2404
2405 if (is_flag_on(IS_SPARC_TARGET)) {
2406 set_dir_flag(NEED_UPDATE);
2407 } else {
2408 ret = update_dircache(file, flags);
2409 if (ret == BAM_ERROR) {
2410 bam_error(_("directory cache update "
2411 "failed for %s\n"), file);
2412 return (-1);
2413 }
2414 }
2415
2416 if (bam_verbose)
2417 bam_print(_(" new %s\n"), file);
2418 return (0);
2419 }
2420
2421 /*
2422 * If we got there, the file is already listed as to be included in the
2423 * iso image. We just need to know if we are going to rebuild it or not
2424 */
2425 if (is_flag_on(IS_SPARC_TARGET) &&
2426 is_dir_flag_on(NEED_UPDATE) && !bam_nowrite())
2427 return (0);
2428 /*
2429 * File exists in old archive. Check if file has changed
2430 */
2431 assert(sz == 2);
2432 bcopy(value, filestat, sizeof (filestat));
2433
2434 if (flags != FTW_D && (filestat[0] != st->st_size ||
2435 filestat[1] != st->st_mtime)) {
2436 if (bam_smf_check) {
2437 safefilep = safefiles;
2438 while (safefilep != NULL &&
2439 safefilep->name[0] != '\0') {
2440 if (regcomp(&re, safefilep->name,
2441 REG_EXTENDED|REG_NOSUB) == 0) {
2442 status = regexec(&re,
2443 file + bam_rootlen, 0, NULL, 0);
2444 regfree(&re);
2445 if (status == 0) {
2446 (void) creat(
2447 NEED_UPDATE_SAFE_FILE,
2448 0644);
2449 return (0);
2450 }
2451 }
2452 safefilep = safefilep->next;
2453 }
2454 }
2455
2456 if (is_flag_on(IS_SPARC_TARGET)) {
2457 set_dir_flag(NEED_UPDATE);
2458 } else {
2459 ret = update_dircache(file, flags);
2460 if (ret == BAM_ERROR) {
2461 bam_error(_("directory cache update failed "
2462 "for %s\n"), file);
2463 return (-1);
2464 }
2465 }
2466
2467 /*
2468 * Update self-assembly file if there are changes in
2469 * /etc/system.d directory
2470 */
2471 if (strstr(file, ETC_SYSTEM_DIR)) {
2472 ret = update_dircache(self_assembly, flags);
2473 if (ret == BAM_ERROR) {
2474 bam_error(_("directory cache update failed "
2475 "for %s\n"), file);
2476 return (-1);
2477 }
2478 }
2479
2480 if (bam_verbose) {
2481 if (bam_smf_check)
2482 bam_print(" %s\n", file);
2483 else
2484 bam_print(_(" changed %s\n"), file);
2485 }
2486 }
2487
2488 return (0);
2489 }
2490
2491 /*
2492 * Remove a directory path recursively
2493 */
2494 static int
rmdir_r(char * path)2495 rmdir_r(char *path)
2496 {
2497 struct dirent *d = NULL;
2498 DIR *dir = NULL;
2499 char tpath[PATH_MAX];
2500 struct stat sb;
2501
2502 if ((dir = opendir(path)) == NULL)
2503 return (-1);
2504
2505 while ((d = readdir(dir)) != NULL) {
2506 if ((strcmp(d->d_name, ".") != 0) &&
2507 (strcmp(d->d_name, "..") != 0)) {
2508 (void) snprintf(tpath, sizeof (tpath), "%s/%s",
2509 path, d->d_name);
2510 if (stat(tpath, &sb) == 0) {
2511 if (sb.st_mode & S_IFDIR)
2512 (void) rmdir_r(tpath);
2513 else
2514 (void) remove(tpath);
2515 }
2516 }
2517 }
2518 return (remove(path));
2519 }
2520
2521 /*
2522 * Check if cache directory exists and, if not, create it and update flags
2523 * accordingly. If the path exists, but it's not a directory, a best effort
2524 * attempt to remove and recreate it is made.
2525 * If the user requested a 'purge', always recreate the directory from scratch.
2526 */
2527 static int
set_cache_dir(char * root)2528 set_cache_dir(char *root)
2529 {
2530 struct stat sb;
2531 int ret = 0;
2532
2533 ret = build_path(get_cachedir(), sizeof (get_cachedir()),
2534 root, ARCHIVE_PREFIX, CACHEDIR_SUFFIX);
2535
2536 if (ret >= sizeof (get_cachedir())) {
2537 bam_error(_("unable to create path on mountpoint %s, "
2538 "path too long\n"), rootbuf);
2539 return (BAM_ERROR);
2540 }
2541
2542 if (bam_purge || is_flag_on(INVALIDATE_CACHE))
2543 (void) rmdir_r(get_cachedir());
2544
2545 if (stat(get_cachedir(), &sb) != 0 || !(S_ISDIR(sb.st_mode))) {
2546 /* best effort unlink attempt, mkdir will catch errors */
2547 (void) unlink(get_cachedir());
2548
2549 if (bam_verbose)
2550 bam_print(_("archive cache directory not found: %s\n"),
2551 get_cachedir());
2552 ret = mkdir(get_cachedir(), DIR_PERMS);
2553 if (ret < 0) {
2554 bam_error(_("mkdir of %s failed: %s\n"),
2555 get_cachedir(), strerror(errno));
2556 get_cachedir()[0] = '\0';
2557 return (ret);
2558 }
2559 set_flag(NEED_CACHE_DIR);
2560 set_dir_flag(NO_EXTEND);
2561 }
2562
2563 return (BAM_SUCCESS);
2564 }
2565
2566 static int
set_update_dir(char * root)2567 set_update_dir(char *root)
2568 {
2569 struct stat sb;
2570 int ret;
2571
2572 if (is_dir_flag_on(NO_EXTEND))
2573 return (BAM_SUCCESS);
2574
2575 if (!bam_extend) {
2576 set_dir_flag(NO_EXTEND);
2577 return (BAM_SUCCESS);
2578 }
2579
2580 ret = build_path(get_updatedir(), sizeof (get_updatedir()),
2581 root, ARCHIVE_PREFIX, UPDATEDIR_SUFFIX);
2582
2583 if (ret >= sizeof (get_updatedir())) {
2584 bam_error(_("unable to create path on mountpoint %s, "
2585 "path too long\n"), rootbuf);
2586 return (BAM_ERROR);
2587 }
2588
2589 if (stat(get_updatedir(), &sb) == 0) {
2590 if (S_ISDIR(sb.st_mode))
2591 ret = rmdir_r(get_updatedir());
2592 else
2593 ret = unlink(get_updatedir());
2594
2595 if (ret != 0)
2596 set_dir_flag(NO_EXTEND);
2597 }
2598
2599 if (mkdir(get_updatedir(), DIR_PERMS) < 0)
2600 set_dir_flag(NO_EXTEND);
2601
2602 return (BAM_SUCCESS);
2603 }
2604
2605 static int
is_valid_archive(char * root)2606 is_valid_archive(char *root)
2607 {
2608 char archive_path[PATH_MAX];
2609 char timestamp_path[PATH_MAX];
2610 struct stat sb, timestamp;
2611 int ret;
2612
2613 ret = build_path(archive_path, sizeof (archive_path),
2614 root, ARCHIVE_PREFIX, ARCHIVE_SUFFIX);
2615
2616 if (ret >= sizeof (archive_path)) {
2617 bam_error(_("unable to create path on mountpoint %s, "
2618 "path too long\n"), rootbuf);
2619 return (BAM_ERROR);
2620 }
2621
2622 if (stat(archive_path, &sb) != 0) {
2623 if (bam_verbose && !bam_check)
2624 bam_print(_("archive not found: %s\n"), archive_path);
2625 set_dir_flag(NEED_UPDATE | NO_EXTEND);
2626 return (BAM_SUCCESS);
2627 }
2628
2629 /*
2630 * The timestamp file is used to prevent stale files in the archive
2631 * cache.
2632 * Stale files can happen if the system is booted back and forth across
2633 * the transition from bootadm-before-the-cache to
2634 * bootadm-after-the-cache, since older versions of bootadm don't know
2635 * about the existence of the archive cache.
2636 *
2637 * Since only bootadm-after-the-cache versions know about about this
2638 * file, we require that the boot archive be older than this file.
2639 */
2640 ret = snprintf(timestamp_path, sizeof (timestamp_path), "%s%s", root,
2641 FILE_STAT_TIMESTAMP);
2642
2643 if (ret >= sizeof (timestamp_path)) {
2644 bam_error(_("unable to create path on mountpoint %s, "
2645 "path too long\n"), rootbuf);
2646 return (BAM_ERROR);
2647 }
2648
2649 if (stat(timestamp_path, ×tamp) != 0 ||
2650 sb.st_mtime > timestamp.st_mtime) {
2651 if (bam_verbose && !bam_check)
2652 bam_print(
2653 _("archive cache is out of sync. Rebuilding.\n"));
2654 /*
2655 * Don't generate a false positive for the boot-archive service
2656 * but trigger an update of the archive cache in
2657 * boot-archive-update.
2658 */
2659 if (bam_smf_check) {
2660 (void) creat(NEED_UPDATE_FILE, 0644);
2661 return (BAM_SUCCESS);
2662 }
2663
2664 set_flag(INVALIDATE_CACHE);
2665 set_dir_flag(NEED_UPDATE | NO_EXTEND);
2666 return (BAM_SUCCESS);
2667 }
2668
2669 if (is_flag_on(IS_SPARC_TARGET))
2670 return (BAM_SUCCESS);
2671
2672 if (bam_extend && sb.st_size > BA_SIZE_MAX) {
2673 if (bam_verbose && !bam_check)
2674 bam_print(_("archive %s is bigger than %d bytes and "
2675 "will be rebuilt\n"), archive_path, BA_SIZE_MAX);
2676 set_dir_flag(NO_EXTEND);
2677 }
2678
2679 return (BAM_SUCCESS);
2680 }
2681
2682 /*
2683 * Check flags and presence of required files and directories.
2684 * The force flag and/or absence of files should
2685 * trigger an update.
2686 * Suppress stdout output if check (-n) option is set
2687 * (as -n should only produce parseable output.)
2688 */
2689 static int
check_flags_and_files(char * root)2690 check_flags_and_files(char *root)
2691 {
2692
2693 struct stat sb;
2694 int ret;
2695
2696 /*
2697 * If archive is missing, create archive
2698 */
2699 ret = is_valid_archive(root);
2700 if (ret == BAM_ERROR)
2701 return (BAM_ERROR);
2702
2703 if (bam_nowrite())
2704 return (BAM_SUCCESS);
2705
2706 /*
2707 * check if cache directories exist on x86.
2708 * check (and always open) the cache file on SPARC.
2709 */
2710 if (is_sparc()) {
2711 ret = snprintf(get_cachedir(),
2712 sizeof (get_cachedir()), "%s%s%s/%s", root,
2713 ARCHIVE_PREFIX, get_machine(), CACHEDIR_SUFFIX);
2714
2715 if (ret >= sizeof (get_cachedir())) {
2716 bam_error(_("unable to create path on mountpoint %s, "
2717 "path too long\n"), rootbuf);
2718 return (BAM_ERROR);
2719 }
2720
2721 if (stat(get_cachedir(), &sb) != 0) {
2722 set_flag(NEED_CACHE_DIR);
2723 set_dir_flag(NEED_UPDATE);
2724 }
2725
2726 walk_arg.sparcfile = fopen(get_cachedir(), "w");
2727 if (walk_arg.sparcfile == NULL) {
2728 bam_error(_("failed to open file: %s: %s\n"),
2729 get_cachedir(), strerror(errno));
2730 return (BAM_ERROR);
2731 }
2732
2733 set_dir_present();
2734 } else {
2735 if (set_cache_dir(root) != 0)
2736 return (BAM_ERROR);
2737
2738 set_dir_present();
2739
2740 if (set_update_dir(root) != 0)
2741 return (BAM_ERROR);
2742 }
2743
2744 /*
2745 * if force, create archive unconditionally
2746 */
2747 if (bam_force) {
2748 set_dir_flag(NEED_UPDATE);
2749 if (bam_verbose)
2750 bam_print(_("forced update of archive requested\n"));
2751 return (BAM_SUCCESS);
2752 }
2753
2754 return (BAM_SUCCESS);
2755 }
2756
2757 static error_t
read_one_list(char * root,filelist_t * flistp,char * filelist)2758 read_one_list(char *root, filelist_t *flistp, char *filelist)
2759 {
2760 char path[PATH_MAX];
2761 FILE *fp;
2762 char buf[BAM_MAXLINE];
2763 const char *fcn = "read_one_list()";
2764
2765 (void) snprintf(path, sizeof (path), "%s%s", root, filelist);
2766
2767 fp = fopen(path, "r");
2768 if (fp == NULL) {
2769 BAM_DPRINTF(("%s: failed to open archive filelist: %s: %s\n",
2770 fcn, path, strerror(errno)));
2771 return (BAM_ERROR);
2772 }
2773 while (s_fgets(buf, sizeof (buf), fp) != NULL) {
2774 /* skip blank lines */
2775 if (strspn(buf, " \t") == strlen(buf))
2776 continue;
2777 append_to_flist(flistp, buf);
2778 }
2779 if (fclose(fp) != 0) {
2780 bam_error(_("failed to close file: %s: %s\n"),
2781 path, strerror(errno));
2782 return (BAM_ERROR);
2783 }
2784 return (BAM_SUCCESS);
2785 }
2786
2787 static error_t
read_list(char * root,filelist_t * flistp)2788 read_list(char *root, filelist_t *flistp)
2789 {
2790 char path[PATH_MAX];
2791 char cmd[PATH_MAX];
2792 struct stat sb;
2793 int n, rval;
2794 const char *fcn = "read_list()";
2795
2796 flistp->head = flistp->tail = NULL;
2797
2798 /*
2799 * build and check path to extract_boot_filelist.ksh
2800 */
2801 n = snprintf(path, sizeof (path), "%s%s", root, EXTRACT_BOOT_FILELIST);
2802 if (n >= sizeof (path)) {
2803 bam_error(_("archive filelist is empty\n"));
2804 return (BAM_ERROR);
2805 }
2806
2807 if (is_safe_exec(path) == BAM_ERROR)
2808 return (BAM_ERROR);
2809
2810 /*
2811 * If extract_boot_filelist is present, exec it, otherwise read
2812 * the filelists directly, for compatibility with older images.
2813 */
2814 if (stat(path, &sb) == 0) {
2815 /*
2816 * build arguments to exec extract_boot_filelist.ksh
2817 */
2818 char *rootarg, *platarg;
2819 int platarglen = 1, rootarglen = 1;
2820 if (strlen(root) > 1)
2821 rootarglen += strlen(root) + strlen("-R ");
2822 if (bam_alt_platform)
2823 platarglen += strlen(bam_platform) + strlen("-p ");
2824 platarg = s_calloc(1, platarglen);
2825 rootarg = s_calloc(1, rootarglen);
2826 *platarg = 0;
2827 *rootarg = 0;
2828
2829 if (strlen(root) > 1) {
2830 (void) snprintf(rootarg, rootarglen,
2831 "-R %s", root);
2832 }
2833 if (bam_alt_platform) {
2834 (void) snprintf(platarg, platarglen,
2835 "-p %s", bam_platform);
2836 }
2837 n = snprintf(cmd, sizeof (cmd), "%s %s %s /%s /%s",
2838 path, rootarg, platarg, BOOT_FILE_LIST, ETC_FILE_LIST);
2839 free(platarg);
2840 free(rootarg);
2841 if (n >= sizeof (cmd)) {
2842 bam_error(_("archive filelist is empty\n"));
2843 return (BAM_ERROR);
2844 }
2845 if (exec_cmd(cmd, flistp) != 0) {
2846 BAM_DPRINTF(("%s: failed to open archive "
2847 "filelist: %s: %s\n", fcn, path, strerror(errno)));
2848 return (BAM_ERROR);
2849 }
2850 } else {
2851 /*
2852 * Read current lists of files - only the first is mandatory
2853 */
2854 rval = read_one_list(root, flistp, BOOT_FILE_LIST);
2855 if (rval != BAM_SUCCESS)
2856 return (rval);
2857 (void) read_one_list(root, flistp, ETC_FILE_LIST);
2858 }
2859
2860 if (flistp->head == NULL) {
2861 bam_error(_("archive filelist is empty\n"));
2862 return (BAM_ERROR);
2863 }
2864
2865 return (BAM_SUCCESS);
2866 }
2867
2868 static void
getoldstat(char * root)2869 getoldstat(char *root)
2870 {
2871 char path[PATH_MAX];
2872 int fd, error;
2873 struct stat sb;
2874 char *ostat;
2875
2876 (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT);
2877 fd = open(path, O_RDONLY);
2878 if (fd == -1) {
2879 if (bam_verbose)
2880 bam_print(_("failed to open file: %s: %s\n"),
2881 path, strerror(errno));
2882 goto out_err;
2883 }
2884
2885 if (fstat(fd, &sb) != 0) {
2886 bam_error(_("stat of file failed: %s: %s\n"), path,
2887 strerror(errno));
2888 goto out_err;
2889 }
2890
2891 ostat = s_calloc(1, sb.st_size);
2892
2893 if (read(fd, ostat, sb.st_size) != sb.st_size) {
2894 bam_error(_("read failed for file: %s: %s\n"), path,
2895 strerror(errno));
2896 free(ostat);
2897 goto out_err;
2898 }
2899
2900 (void) close(fd);
2901 fd = -1;
2902
2903 walk_arg.old_nvlp = NULL;
2904 error = nvlist_unpack(ostat, sb.st_size, &walk_arg.old_nvlp, 0);
2905
2906 free(ostat);
2907
2908 if (error) {
2909 bam_error(_("failed to unpack stat data: %s: %s\n"),
2910 path, strerror(error));
2911 walk_arg.old_nvlp = NULL;
2912 goto out_err;
2913 } else {
2914 return;
2915 }
2916
2917 out_err:
2918 if (fd != -1)
2919 (void) close(fd);
2920 set_dir_flag(NEED_UPDATE);
2921 }
2922
2923 /* Best effort stale entry removal */
2924 static void
delete_stale(char * file)2925 delete_stale(char *file)
2926 {
2927 char path[PATH_MAX];
2928 struct stat sb;
2929
2930 (void) snprintf(path, sizeof (path), "%s/%s", get_cachedir(), file);
2931 if (!bam_check && stat(path, &sb) == 0) {
2932 if (sb.st_mode & S_IFDIR)
2933 (void) rmdir_r(path);
2934 else
2935 (void) unlink(path);
2936
2937 set_dir_flag(NEED_UPDATE | NO_EXTEND);
2938 }
2939 }
2940
2941 /*
2942 * Checks if a file in the current (old) archive has
2943 * been deleted from the root filesystem. This is needed for
2944 * software like Trusted Extensions (TX) that switch early
2945 * in boot based on presence/absence of a kernel module.
2946 */
2947 static void
check4stale(char * root)2948 check4stale(char *root)
2949 {
2950 nvpair_t *nvp;
2951 nvlist_t *nvlp;
2952 char *file;
2953 char path[PATH_MAX];
2954
2955 /*
2956 * Skip stale file check during smf check
2957 */
2958 if (bam_smf_check)
2959 return;
2960
2961 /*
2962 * If we need to (re)create the cache, there's no need to check for
2963 * stale files
2964 */
2965 if (is_flag_on(NEED_CACHE_DIR))
2966 return;
2967
2968 /* Nothing to do if no old stats */
2969 if ((nvlp = walk_arg.old_nvlp) == NULL)
2970 return;
2971
2972 for (nvp = nvlist_next_nvpair(nvlp, NULL); nvp;
2973 nvp = nvlist_next_nvpair(nvlp, nvp)) {
2974 file = nvpair_name(nvp);
2975 if (file == NULL)
2976 continue;
2977 (void) snprintf(path, sizeof (path), "%s/%s",
2978 root, file);
2979 if (access(path, F_OK) < 0) {
2980 if (bam_verbose)
2981 bam_print(_(" stale %s\n"), path);
2982
2983 if (is_flag_on(IS_SPARC_TARGET)) {
2984 set_dir_flag(NEED_UPDATE);
2985 } else {
2986 if (has_cachedir())
2987 delete_stale(file);
2988 }
2989 }
2990 }
2991 }
2992
2993 static void
create_newstat(void)2994 create_newstat(void)
2995 {
2996 int error;
2997
2998 error = nvlist_alloc(&walk_arg.new_nvlp, NV_UNIQUE_NAME, 0);
2999 if (error) {
3000 /*
3001 * Not fatal - we can still create archive
3002 */
3003 walk_arg.new_nvlp = NULL;
3004 bam_error(_("failed to create stat data: %s\n"),
3005 strerror(error));
3006 }
3007 }
3008
3009 static int
walk_list(char * root,filelist_t * flistp)3010 walk_list(char *root, filelist_t *flistp)
3011 {
3012 char path[PATH_MAX];
3013 line_t *lp;
3014
3015 for (lp = flistp->head; lp; lp = lp->next) {
3016 /*
3017 * Don't follow symlinks. A symlink must refer to
3018 * a file that would appear in the archive through
3019 * a direct reference. This matches the archive
3020 * construction behavior.
3021 */
3022 (void) snprintf(path, sizeof (path), "%s%s", root, lp->line);
3023 if (nftw(path, cmpstat, 20, FTW_PHYS) == -1) {
3024 if (is_flag_on(UPDATE_ERROR))
3025 return (BAM_ERROR);
3026 /*
3027 * Some files may not exist.
3028 * For example: etc/rtc_config on a x86 diskless system
3029 * Emit verbose message only
3030 */
3031 if (bam_verbose)
3032 bam_print(_("cannot find: %s: %s\n"),
3033 path, strerror(errno));
3034 }
3035 }
3036
3037 return (BAM_SUCCESS);
3038 }
3039
3040 /*
3041 * Update the timestamp file.
3042 */
3043 static void
update_timestamp(char * root)3044 update_timestamp(char *root)
3045 {
3046 char timestamp_path[PATH_MAX];
3047
3048 /* this path length has already been checked in check_flags_and_files */
3049 (void) snprintf(timestamp_path, sizeof (timestamp_path), "%s%s", root,
3050 FILE_STAT_TIMESTAMP);
3051
3052 /*
3053 * recreate the timestamp file. Since an outdated or absent timestamp
3054 * file translates in a complete rebuild of the archive cache, notify
3055 * the user of the performance issue.
3056 */
3057 if (creat(timestamp_path, FILE_STAT_MODE) < 0) {
3058 bam_error(_("failed to open file: %s: %s\n"), timestamp_path,
3059 strerror(errno));
3060 bam_error(_("failed to update the timestamp file, next"
3061 " archive update may experience reduced performance\n"));
3062 }
3063 }
3064
3065
3066 static void
savenew(char * root)3067 savenew(char *root)
3068 {
3069 char path[PATH_MAX];
3070 char path2[PATH_MAX];
3071 size_t sz;
3072 char *nstat;
3073 int fd, wrote, error;
3074
3075 nstat = NULL;
3076 sz = 0;
3077 error = nvlist_pack(walk_arg.new_nvlp, &nstat, &sz,
3078 NV_ENCODE_XDR, 0);
3079 if (error) {
3080 bam_error(_("failed to pack stat data: %s\n"),
3081 strerror(error));
3082 return;
3083 }
3084
3085 (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT_TMP);
3086 fd = open(path, O_RDWR|O_CREAT|O_TRUNC, FILE_STAT_MODE);
3087 if (fd == -1) {
3088 bam_error(_("failed to open file: %s: %s\n"), path,
3089 strerror(errno));
3090 free(nstat);
3091 return;
3092 }
3093 wrote = write(fd, nstat, sz);
3094 if (wrote != sz) {
3095 bam_error(_("write to file failed: %s: %s\n"), path,
3096 strerror(errno));
3097 (void) close(fd);
3098 free(nstat);
3099 return;
3100 }
3101 (void) close(fd);
3102 free(nstat);
3103
3104 (void) snprintf(path2, sizeof (path2), "%s%s", root, FILE_STAT);
3105 if (rename(path, path2) != 0) {
3106 bam_error(_("rename to file failed: %s: %s\n"), path2,
3107 strerror(errno));
3108 }
3109 }
3110
3111 #define init_walk_args() bzero(&walk_arg, sizeof (walk_arg))
3112
3113 static void
clear_walk_args(void)3114 clear_walk_args(void)
3115 {
3116 nvlist_free(walk_arg.old_nvlp);
3117 nvlist_free(walk_arg.new_nvlp);
3118 if (walk_arg.sparcfile)
3119 (void) fclose(walk_arg.sparcfile);
3120 walk_arg.old_nvlp = NULL;
3121 walk_arg.new_nvlp = NULL;
3122 walk_arg.sparcfile = NULL;
3123 }
3124
3125 /*
3126 * Returns:
3127 * 0 - no update necessary
3128 * 1 - update required.
3129 * BAM_ERROR (-1) - An error occurred
3130 *
3131 * Special handling for check (-n):
3132 * ================================
3133 * The check (-n) option produces parseable output.
3134 * To do this, we suppress all stdout messages unrelated
3135 * to out of sync files.
3136 * All stderr messages are still printed though.
3137 *
3138 */
3139 static int
update_required(char * root)3140 update_required(char *root)
3141 {
3142 struct stat sb;
3143 char path[PATH_MAX];
3144 filelist_t flist;
3145 filelist_t *flistp = &flist;
3146 int ret;
3147
3148 flistp->head = flistp->tail = NULL;
3149
3150 if (is_sparc())
3151 set_flag(IS_SPARC_TARGET);
3152
3153 /*
3154 * Check if cache directories and archives are present
3155 */
3156
3157 ret = check_flags_and_files(root);
3158 if (ret < 0)
3159 return (BAM_ERROR);
3160
3161 /*
3162 * In certain deployment scenarios, filestat may not
3163 * exist. Do not stop the boot process, but trigger an update
3164 * of the archives (which will recreate filestat.ramdisk).
3165 */
3166 if (bam_smf_check) {
3167 (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT);
3168 if (stat(path, &sb) != 0) {
3169 (void) creat(NEED_UPDATE_FILE, 0644);
3170 return (0);
3171 }
3172 }
3173
3174 getoldstat(root);
3175
3176 /*
3177 * Check if the archive contains files that are no longer
3178 * present on the root filesystem.
3179 */
3180 check4stale(root);
3181
3182 /*
3183 * read list of files
3184 */
3185 if (read_list(root, flistp) != BAM_SUCCESS) {
3186 clear_walk_args();
3187 return (BAM_ERROR);
3188 }
3189
3190 assert(flistp->head && flistp->tail);
3191
3192 /*
3193 * At this point either the update is required
3194 * or the decision is pending. In either case
3195 * we need to create new stat nvlist
3196 */
3197 create_newstat();
3198 /*
3199 * This walk does 2 things:
3200 * - gets new stat data for every file
3201 * - (optional) compare old and new stat data
3202 */
3203 ret = walk_list(root, &flist);
3204
3205 /* done with the file list */
3206 filelist_free(flistp);
3207
3208 /* something went wrong */
3209
3210 if (ret == BAM_ERROR) {
3211 bam_error(_("Failed to gather cache files, archives "
3212 "generation aborted\n"));
3213 return (BAM_ERROR);
3214 }
3215
3216 if (walk_arg.new_nvlp == NULL) {
3217 if (walk_arg.sparcfile != NULL)
3218 (void) fclose(walk_arg.sparcfile);
3219 bam_error(_("cannot create new stat data\n"));
3220 }
3221
3222 /* If nothing was updated, discard newstat. */
3223
3224 if (!is_dir_flag_on(NEED_UPDATE)) {
3225 clear_walk_args();
3226 return (0);
3227 }
3228
3229 if (walk_arg.sparcfile != NULL)
3230 (void) fclose(walk_arg.sparcfile);
3231
3232 return (1);
3233 }
3234
3235 static int
flushfs(char * root)3236 flushfs(char *root)
3237 {
3238 char cmd[PATH_MAX + 30];
3239
3240 (void) snprintf(cmd, sizeof (cmd), "%s -f \"%s\" 2>/dev/null",
3241 LOCKFS_PATH, root);
3242
3243 return (exec_cmd(cmd, NULL));
3244 }
3245
3246 static int
do_archive_copy(char * source,char * dest)3247 do_archive_copy(char *source, char *dest)
3248 {
3249
3250 sync();
3251
3252 /* the equivalent of mv archive-new-$pid boot_archive */
3253 if (rename(source, dest) != 0) {
3254 (void) unlink(source);
3255 return (BAM_ERROR);
3256 }
3257
3258 if (flushfs(bam_root) != 0)
3259 sync();
3260
3261 return (BAM_SUCCESS);
3262 }
3263
3264 static int
check_cmdline(filelist_t flist)3265 check_cmdline(filelist_t flist)
3266 {
3267 line_t *lp;
3268
3269 for (lp = flist.head; lp; lp = lp->next) {
3270 if (strstr(lp->line, "Error:") != NULL ||
3271 strstr(lp->line, "Inode number overflow") != NULL) {
3272 (void) fprintf(stderr, "%s\n", lp->line);
3273 return (BAM_ERROR);
3274 }
3275 }
3276
3277 return (BAM_SUCCESS);
3278 }
3279
3280 static void
dump_errormsg(filelist_t flist)3281 dump_errormsg(filelist_t flist)
3282 {
3283 line_t *lp;
3284
3285 for (lp = flist.head; lp; lp = lp->next)
3286 (void) fprintf(stderr, "%s\n", lp->line);
3287 }
3288
3289 static int
check_archive(char * dest)3290 check_archive(char *dest)
3291 {
3292 struct stat sb;
3293
3294 if (stat(dest, &sb) != 0 || !S_ISREG(sb.st_mode) ||
3295 sb.st_size < 10000) {
3296 bam_error(_("archive file %s not generated correctly\n"), dest);
3297 (void) unlink(dest);
3298 return (BAM_ERROR);
3299 }
3300
3301 return (BAM_SUCCESS);
3302 }
3303
3304 static boolean_t
is_be(char * root)3305 is_be(char *root)
3306 {
3307 zfs_handle_t *zhp;
3308 libzfs_handle_t *hdl;
3309 be_node_list_t *be_nodes = NULL;
3310 be_node_list_t *cur_be;
3311 boolean_t be_exist = B_FALSE;
3312 char ds_path[ZFS_MAX_DATASET_NAME_LEN];
3313
3314 if (!is_zfs(root))
3315 return (B_FALSE);
3316 /*
3317 * Get dataset for mountpoint
3318 */
3319 if ((hdl = libzfs_init()) == NULL)
3320 return (B_FALSE);
3321
3322 if ((zhp = zfs_path_to_zhandle(hdl, root,
3323 ZFS_TYPE_FILESYSTEM)) == NULL) {
3324 libzfs_fini(hdl);
3325 return (B_FALSE);
3326 }
3327
3328 (void) strlcpy(ds_path, zfs_get_name(zhp), sizeof (ds_path));
3329
3330 /*
3331 * Check if the current dataset is BE
3332 */
3333 if (be_list(NULL, &be_nodes, BE_LIST_DEFAULT) == BE_SUCCESS) {
3334 for (cur_be = be_nodes; cur_be != NULL;
3335 cur_be = cur_be->be_next_node) {
3336
3337 /*
3338 * Because we guarantee that cur_be->be_root_ds
3339 * is null-terminated by internal data structure,
3340 * we can safely use strcmp()
3341 */
3342 if (strcmp(ds_path, cur_be->be_root_ds) == 0) {
3343 be_exist = B_TRUE;
3344 break;
3345 }
3346 }
3347 be_free_list(be_nodes);
3348 }
3349 zfs_close(zhp);
3350 libzfs_fini(hdl);
3351
3352 return (be_exist);
3353 }
3354
3355 /*
3356 * Returns B_TRUE if mkiso is in the expected PATH and should be used,
3357 * B_FALSE otherwise
3358 */
3359 static boolean_t
use_mkisofs()3360 use_mkisofs()
3361 {
3362 scf_simple_prop_t *prop;
3363 char *format = NULL;
3364 boolean_t ret;
3365
3366 /* Check whether the mkisofs binary is in the expected location */
3367 if (access(MKISOFS_PATH, X_OK) != 0) {
3368 if (bam_verbose)
3369 bam_print("mkisofs not found\n");
3370 return (B_FALSE);
3371 }
3372
3373 if (bam_format == BAM_FORMAT_HSFS) {
3374 if (bam_verbose)
3375 bam_print("-F specified HSFS");
3376 return (B_TRUE);
3377 }
3378
3379 /* If working on an alt-root, do not use HSFS unless asked via -F */
3380 if (bam_alt_root)
3381 return (B_FALSE);
3382
3383 /*
3384 * Then check that the system/boot-archive config/format property
3385 * is "hsfs" or empty.
3386 */
3387 if ((prop = scf_simple_prop_get(NULL, BOOT_ARCHIVE_FMRI, SCF_PG_CONFIG,
3388 SCF_PROPERTY_FORMAT)) == NULL) {
3389 /* Could not find property, use mkisofs */
3390 if (bam_verbose) {
3391 bam_print(
3392 "%s does not have %s/%s property, using mkisofs\n",
3393 BOOT_ARCHIVE_FMRI, SCF_PG_CONFIG,
3394 SCF_PROPERTY_FORMAT);
3395 }
3396 return (B_TRUE);
3397 }
3398 if (scf_simple_prop_numvalues(prop) < 0 ||
3399 (format = scf_simple_prop_next_astring(prop)) == NULL)
3400 ret = B_TRUE;
3401 else
3402 ret = strcmp(format, "hsfs") == 0 ? B_TRUE : B_FALSE;
3403 if (bam_verbose) {
3404 if (ret)
3405 bam_print("Creating hsfs boot archive\n");
3406 else
3407 bam_print("Creating %s boot archive\n", format);
3408 }
3409 scf_simple_prop_free(prop);
3410 return (ret);
3411 }
3412
3413 #define MKISO_PARAMS " -quiet -graft-points -dlrDJN -relaxed-filenames "
3414
3415 static int
create_sparc_archive(char * archive,char * tempname,char * bootblk,char * list)3416 create_sparc_archive(char *archive, char *tempname, char *bootblk, char *list)
3417 {
3418 int ret;
3419 char cmdline[3 * PATH_MAX + 64];
3420 filelist_t flist = {0};
3421 const char *func = "create_sparc_archive()";
3422
3423 if (access(bootblk, R_OK) == 1) {
3424 bam_error(_("unable to access bootblk file : %s\n"), bootblk);
3425 return (BAM_ERROR);
3426 }
3427
3428 /*
3429 * Prepare mkisofs command line and execute it
3430 */
3431 (void) snprintf(cmdline, sizeof (cmdline), "%s %s -G %s -o \"%s\" "
3432 "-path-list \"%s\" 2>&1", MKISOFS_PATH, MKISO_PARAMS, bootblk,
3433 tempname, list);
3434
3435 BAM_DPRINTF(("%s: executing: %s\n", func, cmdline));
3436
3437 ret = exec_cmd(cmdline, &flist);
3438 if (ret != 0 || check_cmdline(flist) == BAM_ERROR) {
3439 dump_errormsg(flist);
3440 goto out_err;
3441 }
3442
3443 filelist_free(&flist);
3444
3445 /*
3446 * Prepare dd command line to copy the bootblk on the new archive and
3447 * execute it
3448 */
3449 (void) snprintf(cmdline, sizeof (cmdline), "%s if=\"%s\" of=\"%s\""
3450 " bs=1b oseek=1 count=15 conv=notrunc conv=sync 2>&1", DD_PATH_USR,
3451 bootblk, tempname);
3452
3453 BAM_DPRINTF(("%s: executing: %s\n", func, cmdline));
3454
3455 ret = exec_cmd(cmdline, &flist);
3456 if (ret != 0 || check_cmdline(flist) == BAM_ERROR)
3457 goto out_err;
3458
3459 filelist_free(&flist);
3460
3461 /* Did we get a valid archive ? */
3462 if (check_archive(tempname) == BAM_ERROR)
3463 return (BAM_ERROR);
3464
3465 return (do_archive_copy(tempname, archive));
3466
3467 out_err:
3468 filelist_free(&flist);
3469 bam_error(_("boot-archive creation FAILED, command: '%s'\n"), cmdline);
3470 (void) unlink(tempname);
3471 return (BAM_ERROR);
3472 }
3473
3474 static unsigned int
from_733(unsigned char * s)3475 from_733(unsigned char *s)
3476 {
3477 int i;
3478 unsigned int ret = 0;
3479
3480 for (i = 0; i < 4; i++)
3481 ret |= s[i] << (8 * i);
3482
3483 return (ret);
3484 }
3485
3486 static void
to_733(unsigned char * s,unsigned int val)3487 to_733(unsigned char *s, unsigned int val)
3488 {
3489 int i;
3490
3491 for (i = 0; i < 4; i++)
3492 s[i] = s[7-i] = (val >> (8 * i)) & 0xFF;
3493 }
3494
3495 /*
3496 * creates sha1 hash of archive
3497 */
3498 static int
digest_archive(const char * archive)3499 digest_archive(const char *archive)
3500 {
3501 char *archive_hash;
3502 char *hash;
3503 int ret;
3504 FILE *fp;
3505
3506 (void) asprintf(&archive_hash, "%s.hash", archive);
3507 if (archive_hash == NULL)
3508 return (BAM_ERROR);
3509
3510 if ((ret = bootadm_digest(archive, &hash)) == BAM_ERROR) {
3511 free(archive_hash);
3512 return (ret);
3513 }
3514
3515 fp = fopen(archive_hash, "w");
3516 if (fp == NULL) {
3517 free(archive_hash);
3518 free(hash);
3519 return (BAM_ERROR);
3520 }
3521
3522 (void) fprintf(fp, "%s\n", hash);
3523 (void) fclose(fp);
3524 free(hash);
3525 free(archive_hash);
3526 return (BAM_SUCCESS);
3527 }
3528
3529 /*
3530 * Extends the current boot archive without recreating it from scratch
3531 */
3532 static int
extend_iso_archive(char * archive,char * tempname,char * update_dir)3533 extend_iso_archive(char *archive, char *tempname, char *update_dir)
3534 {
3535 int fd = -1, newfd = -1, ret, i;
3536 int next_session = 0, new_size = 0;
3537 char cmdline[3 * PATH_MAX + 64];
3538 const char *func = "extend_iso_archive()";
3539 filelist_t flist = {0};
3540 struct iso_pdesc saved_desc[MAX_IVDs];
3541
3542 fd = open(archive, O_RDWR);
3543 if (fd == -1) {
3544 if (bam_verbose)
3545 bam_error(_("failed to open file: %s: %s\n"),
3546 archive, strerror(errno));
3547 goto out_err;
3548 }
3549
3550 /*
3551 * A partial read is likely due to a corrupted file
3552 */
3553 ret = pread64(fd, saved_desc, sizeof (saved_desc),
3554 VOLDESC_OFF * CD_BLOCK);
3555 if (ret != sizeof (saved_desc)) {
3556 if (bam_verbose)
3557 bam_error(_("read failed for file: %s: %s\n"),
3558 archive, strerror(errno));
3559 goto out_err;
3560 }
3561
3562 if (memcmp(saved_desc[0].type, "\1CD001", 6)) {
3563 if (bam_verbose)
3564 bam_error(_("iso descriptor signature for %s is "
3565 "invalid\n"), archive);
3566 goto out_err;
3567 }
3568
3569 /*
3570 * Read primary descriptor and locate next_session offset (it should
3571 * point to the end of the archive)
3572 */
3573 next_session = P2ROUNDUP(from_733(saved_desc[0].volume_space_size), 16);
3574
3575 (void) snprintf(cmdline, sizeof (cmdline), "%s -C 16,%d -M %s %s -o \""
3576 "%s\" \"%s\" 2>&1", MKISOFS_PATH, next_session, archive,
3577 MKISO_PARAMS, tempname, update_dir);
3578
3579 BAM_DPRINTF(("%s: executing: %s\n", func, cmdline));
3580
3581 ret = exec_cmd(cmdline, &flist);
3582 if (ret != 0 || check_cmdline(flist) == BAM_ERROR) {
3583 if (bam_verbose) {
3584 bam_error(_("Command '%s' failed while generating "
3585 "multisession archive\n"), cmdline);
3586 dump_errormsg(flist);
3587 }
3588 goto out_flist_err;
3589 }
3590 filelist_free(&flist);
3591
3592 newfd = open(tempname, O_RDONLY);
3593 if (newfd == -1) {
3594 if (bam_verbose)
3595 bam_error(_("failed to open file: %s: %s\n"),
3596 archive, strerror(errno));
3597 goto out_err;
3598 }
3599
3600 ret = pread64(newfd, saved_desc, sizeof (saved_desc),
3601 VOLDESC_OFF * CD_BLOCK);
3602 if (ret != sizeof (saved_desc)) {
3603 if (bam_verbose)
3604 bam_error(_("read failed for file: %s: %s\n"),
3605 archive, strerror(errno));
3606 goto out_err;
3607 }
3608
3609 if (memcmp(saved_desc[0].type, "\1CD001", 6)) {
3610 if (bam_verbose)
3611 bam_error(_("iso descriptor signature for %s is "
3612 "invalid\n"), archive);
3613 goto out_err;
3614 }
3615
3616 new_size = from_733(saved_desc[0].volume_space_size) + next_session;
3617 to_733(saved_desc[0].volume_space_size, new_size);
3618
3619 for (i = 1; i < MAX_IVDs; i++) {
3620 if (saved_desc[i].type[0] == (unsigned char)255)
3621 break;
3622 if (memcmp(saved_desc[i].id, "CD001", 5))
3623 break;
3624
3625 if (bam_verbose)
3626 bam_print("%s: Updating descriptor entry [%d]\n", func,
3627 i);
3628
3629 to_733(saved_desc[i].volume_space_size, new_size);
3630 }
3631
3632 ret = pwrite64(fd, saved_desc, DVD_BLOCK, VOLDESC_OFF*CD_BLOCK);
3633 if (ret != DVD_BLOCK) {
3634 if (bam_verbose)
3635 bam_error(_("write to file failed: %s: %s\n"),
3636 archive, strerror(errno));
3637 goto out_err;
3638 }
3639 (void) close(newfd);
3640 newfd = -1;
3641
3642 ret = fsync(fd);
3643 if (ret != 0)
3644 sync();
3645
3646 ret = close(fd);
3647 if (ret != 0) {
3648 if (bam_verbose)
3649 bam_error(_("failed to close file: %s: %s\n"),
3650 archive, strerror(errno));
3651 return (BAM_ERROR);
3652 }
3653 fd = -1;
3654
3655 (void) snprintf(cmdline, sizeof (cmdline), "%s if=%s of=%s bs=32k "
3656 "seek=%d conv=sync 2>&1", DD_PATH_USR, tempname, archive,
3657 (next_session/16));
3658
3659 BAM_DPRINTF(("%s: executing: %s\n", func, cmdline));
3660
3661 ret = exec_cmd(cmdline, &flist);
3662 if (ret != 0 || check_cmdline(flist) == BAM_ERROR) {
3663 if (bam_verbose)
3664 bam_error(_("Command '%s' failed while generating "
3665 "multisession archive\n"), cmdline);
3666 goto out_flist_err;
3667 }
3668 filelist_free(&flist);
3669
3670 (void) unlink(tempname);
3671
3672 if (digest_archive(archive) == BAM_ERROR && bam_verbose)
3673 bam_print("boot archive hashing failed\n");
3674
3675 if (flushfs(bam_root) != 0)
3676 sync();
3677
3678 if (bam_verbose)
3679 bam_print("boot archive updated successfully\n");
3680
3681 return (BAM_SUCCESS);
3682
3683 out_flist_err:
3684 filelist_free(&flist);
3685 out_err:
3686 if (fd != -1)
3687 (void) close(fd);
3688 if (newfd != -1)
3689 (void) close(newfd);
3690 return (BAM_ERROR);
3691 }
3692
3693 static int
create_x86_archive(char * archive,char * tempname,char * update_dir)3694 create_x86_archive(char *archive, char *tempname, char *update_dir)
3695 {
3696 int ret;
3697 char cmdline[3 * PATH_MAX + 64];
3698 filelist_t flist = {0};
3699 const char *func = "create_x86_archive()";
3700
3701 (void) snprintf(cmdline, sizeof (cmdline), "%s %s -o \"%s\" \"%s\" "
3702 "2>&1", MKISOFS_PATH, MKISO_PARAMS, tempname, update_dir);
3703
3704 BAM_DPRINTF(("%s: executing: %s\n", func, cmdline));
3705
3706 ret = exec_cmd(cmdline, &flist);
3707 if (ret != 0 || check_cmdline(flist) == BAM_ERROR) {
3708 bam_error(_("boot-archive creation FAILED, command: '%s'\n"),
3709 cmdline);
3710 dump_errormsg(flist);
3711 filelist_free(&flist);
3712 (void) unlink(tempname);
3713 return (BAM_ERROR);
3714 }
3715
3716 filelist_free(&flist);
3717
3718 if (check_archive(tempname) == BAM_ERROR)
3719 return (BAM_ERROR);
3720
3721 return (do_archive_copy(tempname, archive));
3722 }
3723
3724 static int
mkisofs_archive(char * root)3725 mkisofs_archive(char *root)
3726 {
3727 int ret;
3728 char suffix[20];
3729 char temp[PATH_MAX];
3730 char bootblk[PATH_MAX];
3731 char boot_archive[PATH_MAX];
3732
3733 ret = snprintf(suffix, sizeof (suffix), "/archive-new-%d", getpid());
3734 if (ret >= sizeof (suffix))
3735 goto out_path_err;
3736
3737 ret = build_path(temp, sizeof (temp), root, ARCHIVE_PREFIX, suffix);
3738
3739 if (ret >= sizeof (temp))
3740 goto out_path_err;
3741
3742 ret = build_path(boot_archive, sizeof (boot_archive), root,
3743 ARCHIVE_PREFIX, ARCHIVE_SUFFIX);
3744
3745 if (ret >= sizeof (boot_archive))
3746 goto out_path_err;
3747
3748 bam_print("updating %s (HSFS)\n",
3749 boot_archive[1] == '/' ? boot_archive + 1 : boot_archive);
3750
3751 if (is_flag_on(IS_SPARC_TARGET)) {
3752 ret = snprintf(bootblk, sizeof (bootblk),
3753 "%s/platform/%s/lib/fs/hsfs/bootblk", root, get_machine());
3754 if (ret >= sizeof (bootblk))
3755 goto out_path_err;
3756
3757 ret = create_sparc_archive(boot_archive, temp, bootblk,
3758 get_cachedir());
3759 } else {
3760 if (!is_dir_flag_on(NO_EXTEND)) {
3761 if (bam_verbose)
3762 bam_print("Attempting to extend x86 archive: "
3763 "%s\n", boot_archive);
3764
3765 ret = extend_iso_archive(boot_archive, temp,
3766 get_updatedir());
3767 if (ret == BAM_SUCCESS) {
3768 if (bam_verbose)
3769 bam_print("Successfully extended %s\n",
3770 boot_archive);
3771
3772 (void) rmdir_r(get_updatedir());
3773 return (BAM_SUCCESS);
3774 }
3775 }
3776 /*
3777 * The boot archive will be recreated from scratch. We get here
3778 * if at least one of these conditions is true:
3779 * - bootadm was called without the -e switch
3780 * - the archive (or the archive cache) doesn't exist
3781 * - archive size is bigger than BA_SIZE_MAX
3782 * - more than COUNT_MAX files need to be updated
3783 * - an error occourred either populating the /updates directory
3784 * or extend_iso_archive() failed
3785 */
3786 if (bam_verbose)
3787 bam_print("Unable to extend %s... rebuilding archive\n",
3788 boot_archive);
3789
3790 if (get_updatedir()[0] != '\0')
3791 (void)