Print this page
9696 add /etc/system.d support
Portions contributed by: Andy Fiddaman <andy@omniosce.org>
Reviewed by: Hans Rosenfeld <hans.rosenfeld@joyent.com>
Reviewed by: Peter Tribble <peter.tribble@gmail.com>
Reviewed by: C Fraire <cfraire@me.com>
Reviewed by: Toomas Soome <tsoome@me.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/boot/bootadm/bootadm.c
+++ new/usr/src/cmd/boot/bootadm/bootadm.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright 2012 Milan Jurik. All rights reserved.
25 25 * Copyright (c) 2015 by Delphix. All rights reserved.
26 26 * Copyright 2016 Toomas Soome <tsoome@me.com>
27 - * Copyright 2016 Nexenta Systems, Inc.
27 + * Copyright 2017 Nexenta Systems, Inc.
28 28 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
29 29 */
30 30
31 31 /*
32 32 * bootadm(1M) is a new utility for managing bootability of
33 33 * Solaris *Newboot* environments. It has two primary tasks:
34 34 * - Allow end users to manage bootability of Newboot Solaris instances
35 35 * - Provide services to other subsystems in Solaris (primarily Install)
36 36 */
37 37
38 38 /* Headers */
39 39 #include <stdio.h>
40 40 #include <errno.h>
41 41 #include <stdlib.h>
42 42 #include <string.h>
43 43 #include <unistd.h>
44 44 #include <sys/types.h>
45 45 #include <sys/stat.h>
46 46 #include <alloca.h>
47 47 #include <stdarg.h>
48 48 #include <limits.h>
49 49 #include <signal.h>
50 50 #include <sys/wait.h>
51 51 #include <sys/mnttab.h>
52 52 #include <sys/mntent.h>
53 53 #include <sys/statvfs.h>
54 54 #include <libnvpair.h>
55 55 #include <ftw.h>
56 56 #include <fcntl.h>
57 57 #include <strings.h>
58 58 #include <utime.h>
59 59 #include <sys/systeminfo.h>
60 60 #include <sys/dktp/fdisk.h>
61 61 #include <sys/param.h>
62 62 #include <dirent.h>
63 63 #include <ctype.h>
64 64 #include <libgen.h>
65 65 #include <sys/sysmacros.h>
66 66 #include <sys/elf.h>
67 67 #include <libscf.h>
68 68 #include <zlib.h>
69 69 #include <sys/lockfs.h>
70 70 #include <sys/filio.h>
71 71 #include <libbe.h>
72 72 #include <deflt.h>
73 73 #ifdef i386
74 74 #include <libfdisk.h>
75 75 #endif
76 76
77 77 #if !defined(_OBP)
78 78 #include <sys/ucode.h>
79 79 #endif
80 80
81 81 #include <pwd.h>
82 82 #include <grp.h>
83 83 #include <device_info.h>
84 84 #include <sys/vtoc.h>
85 85 #include <sys/efi_partition.h>
86 86 #include <regex.h>
87 87 #include <locale.h>
88 88 #include <sys/mkdev.h>
89 89
90 90 #include "bootadm.h"
91 91
92 92 #ifndef TEXT_DOMAIN
93 93 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
94 94 #endif /* TEXT_DOMAIN */
95 95
96 96 /* Type definitions */
97 97
98 98 /* Primary subcmds */
99 99 typedef enum {
100 100 BAM_MENU = 3,
101 101 BAM_ARCHIVE,
102 102 BAM_INSTALL
103 103 } subcmd_t;
104 104
105 105 #define LINE_INIT 0 /* lineNum initial value */
106 106 #define ENTRY_INIT -1 /* entryNum initial value */
107 107 #define ALL_ENTRIES -2 /* selects all boot entries */
108 108
109 109 #define PARTNO_NOTFOUND -1 /* Solaris partition not found */
110 110 #define PARTNO_EFI -2 /* EFI partition table found */
111 111
112 112 #define GRUB_DIR "/boot/grub"
113 113 #define GRUB_STAGE2 GRUB_DIR "/stage2"
114 114 #define GRUB_MENU "/boot/grub/menu.lst"
115 115 #define MENU_TMP "/boot/grub/menu.lst.tmp"
116 116 #define GRUB_BACKUP_MENU "/etc/lu/GRUB_backup_menu"
117 117 #define RAMDISK_SPECIAL "/devices/ramdisk"
118 118 #define STUBBOOT "/stubboot"
119 119 #define MULTIBOOT "/platform/i86pc/multiboot"
120 120 #define GRUBSIGN_DIR "/boot/grub/bootsign"
121 121 #define GRUBSIGN_BACKUP "/etc/bootsign"
122 122 #define GRUBSIGN_UFS_PREFIX "rootfs"
123 123 #define GRUBSIGN_ZFS_PREFIX "pool_"
124 124 #define GRUBSIGN_LU_PREFIX "BE_"
125 125 #define UFS_SIGNATURE_LIST "/var/run/grub_ufs_signatures"
126 126 #define ZFS_LEGACY_MNTPT "/tmp/bootadm_mnt_zfs_legacy"
127 127
128 128 /* SMF */
129 129 #define BOOT_ARCHIVE_FMRI "system/boot-archive:default"
130 130 #define SCF_PG_CONFIG "config"
131 131 #define SCF_PROPERTY_FORMAT "format"
132 132
133 133 /* BE defaults */
134 134 #define BE_DEFAULTS "/etc/default/be"
135 135 #define BE_DFLT_BE_HAS_GRUB "BE_HAS_GRUB="
136 136
137 137 #define BOOTADM_RDONLY_TEST "BOOTADM_RDONLY_TEST"
138 138
139 139 /* lock related */
140 140 #define BAM_LOCK_FILE "/var/run/bootadm.lock"
141 141 #define LOCK_FILE_PERMS (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
142 142
143 143 #define CREATE_RAMDISK "boot/solaris/bin/create_ramdisk"
144 144 #define CREATE_DISKMAP "boot/solaris/bin/create_diskmap"
145 145 #define EXTRACT_BOOT_FILELIST "boot/solaris/bin/extract_boot_filelist"
146 146 #define GRUBDISK_MAP "/var/run/solaris_grubdisk.map"
147 147
148 148 #define GRUB_slice "/etc/lu/GRUB_slice"
149 149 #define GRUB_root "/etc/lu/GRUB_root"
150 150 #define GRUB_fdisk "/etc/lu/GRUB_fdisk"
151 151 #define GRUB_fdisk_target "/etc/lu/GRUB_fdisk_target"
152 152 #define FINDROOT_INSTALLGRUB "/etc/lu/installgrub.findroot"
↓ open down ↓ |
115 lines elided |
↑ open up ↑ |
153 153 #define LULIB "/usr/lib/lu/lulib"
154 154 #define LULIB_PROPAGATE_FILE "lulib_propagate_file"
155 155 #define CKSUM "/usr/bin/cksum"
156 156 #define LU_MENU_CKSUM "/etc/lu/menu.cksum"
157 157 #define BOOTADM "/sbin/bootadm"
158 158
159 159 #define INSTALLGRUB "/sbin/installgrub"
160 160 #define STAGE1 "/boot/grub/stage1"
161 161 #define STAGE2 "/boot/grub/stage2"
162 162
163 +#define ETC_SYSTEM_DIR "etc/system.d"
164 +#define SELF_ASSEMBLY "etc/system.d/.self-assembly"
165 +
163 166 /*
164 167 * Default file attributes
165 168 */
166 169 #define DEFAULT_DEV_MODE 0644 /* default permissions */
167 170 #define DEFAULT_DEV_UID 0 /* user root */
168 171 #define DEFAULT_DEV_GID 3 /* group sys */
169 172
170 173 /*
171 174 * Menu related
172 175 * menu_cmd_t and menu_cmds must be kept in sync
173 176 */
174 177 char *menu_cmds[] = {
175 178 "default", /* DEFAULT_CMD */
176 179 "timeout", /* TIMEOUT_CMD */
177 180 "title", /* TITLE_CMD */
178 181 "root", /* ROOT_CMD */
179 182 "kernel", /* KERNEL_CMD */
180 183 "kernel$", /* KERNEL_DOLLAR_CMD */
181 184 "module", /* MODULE_CMD */
182 185 "module$", /* MODULE_DOLLAR_CMD */
183 186 " ", /* SEP_CMD */
184 187 "#", /* COMMENT_CMD */
185 188 "chainloader", /* CHAINLOADER_CMD */
186 189 "args", /* ARGS_CMD */
187 190 "findroot", /* FINDROOT_CMD */
188 191 "bootfs", /* BOOTFS_CMD */
189 192 NULL
190 193 };
191 194
192 195 char *bam_formats[] = {
193 196 "hsfs",
194 197 "ufs",
195 198 "cpio",
196 199 "ufs-nocompress",
197 200 NULL
198 201 };
199 202 #define BAM_FORMAT_UNSET -1
200 203 #define BAM_FORMAT_HSFS 0
201 204 short bam_format = BAM_FORMAT_UNSET;
202 205
203 206 #define OPT_ENTRY_NUM "entry"
204 207
205 208 /*
206 209 * exec_cmd related
207 210 */
208 211 typedef struct {
209 212 line_t *head;
210 213 line_t *tail;
211 214 } filelist_t;
212 215
213 216 #define BOOT_FILE_LIST "boot/solaris/filelist.ramdisk"
214 217 #define ETC_FILE_LIST "etc/boot/solaris/filelist.ramdisk"
215 218
216 219 #define FILE_STAT "boot/solaris/filestat.ramdisk"
217 220 #define FILE_STAT_TMP "boot/solaris/filestat.ramdisk.tmp"
218 221 #define DIR_PERMS (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
219 222 #define FILE_STAT_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
220 223
221 224 #define FILE_STAT_TIMESTAMP "boot/solaris/timestamp.cache"
222 225
223 226 /* Globals */
224 227 int bam_verbose;
225 228 int bam_force;
226 229 int bam_debug;
227 230 int bam_skip_lock;
228 231 static char *prog;
229 232 static subcmd_t bam_cmd;
230 233 char *bam_root;
231 234 int bam_rootlen;
232 235 static int bam_root_readonly;
233 236 int bam_alt_root;
234 237 static int bam_extend = 0;
235 238 static int bam_purge = 0;
236 239 static char *bam_subcmd;
237 240 static char *bam_opt;
↓ open down ↓ |
65 lines elided |
↑ open up ↑ |
238 241 static char **bam_argv;
239 242 static char *bam_pool;
240 243 static int bam_argc;
241 244 static int bam_check;
242 245 static int bam_saved_check;
243 246 static int bam_smf_check;
244 247 static int bam_lock_fd = -1;
245 248 static int bam_zfs;
246 249 static int bam_mbr;
247 250 char rootbuf[PATH_MAX] = "/";
251 +static char self_assembly[PATH_MAX];
248 252 static int bam_update_all;
249 253 static int bam_alt_platform;
250 254 static char *bam_platform;
251 255 static char *bam_home_env = NULL;
252 256
253 257 /* function prototypes */
254 258 static void parse_args_internal(int, char *[]);
255 259 static void parse_args(int, char *argv[]);
256 260 static error_t bam_menu(char *, char *, int, char *[]);
257 261 static error_t bam_install(char *, char *);
258 262 static error_t bam_archive(char *, char *);
259 263
260 264 static void bam_lock(void);
261 265 static void bam_unlock(void);
262 266
263 267 static int exec_cmd(char *, filelist_t *);
264 268 static error_t read_globals(menu_t *, char *, char *, int);
265 269 static int menu_on_bootdisk(char *os_root, char *menu_root);
266 270 static menu_t *menu_read(char *);
267 271 static error_t menu_write(char *, menu_t *);
268 272 static void linelist_free(line_t *);
269 273 static void menu_free(menu_t *);
270 274 static void filelist_free(filelist_t *);
271 275 static error_t list2file(char *, char *, char *, line_t *);
272 276 static error_t list_entry(menu_t *, char *, char *);
273 277 static error_t list_setting(menu_t *, char *, char *);
274 278 static error_t delete_all_entries(menu_t *, char *, char *);
275 279 static error_t update_entry(menu_t *mp, char *menu_root, char *opt);
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
276 280 static error_t update_temp(menu_t *mp, char *dummy, char *opt);
277 281
278 282 static error_t install_bootloader(void);
279 283 static error_t update_archive(char *, char *);
280 284 static error_t list_archive(char *, char *);
281 285 static error_t update_all(char *, char *);
282 286 static error_t read_list(char *, filelist_t *);
283 287 static error_t set_option(menu_t *, char *, char *);
284 288 static error_t set_kernel(menu_t *, menu_cmd_t, char *, char *, size_t);
285 289 static error_t get_kernel(menu_t *, menu_cmd_t, char *, size_t);
290 +static error_t build_etc_system_dir(char *);
286 291 static char *expand_path(const char *);
287 292
288 293 static long s_strtol(char *);
289 294 static int s_fputs(char *, FILE *);
290 295
291 296 static int is_amd64(void);
292 297 static char *get_machine(void);
293 298 static void append_to_flist(filelist_t *, char *);
294 299 static int ufs_add_to_sign_list(char *sign);
295 300 static error_t synchronize_BE_menu(void);
296 301
297 302 #if !defined(_OBP)
298 303 static void ucode_install();
299 304 #endif
300 305
301 306 /* Menu related sub commands */
302 307 static subcmd_defn_t menu_subcmds[] = {
303 308 "set_option", OPT_ABSENT, set_option, 0, /* PUB */
304 309 "list_entry", OPT_OPTIONAL, list_entry, 1, /* PUB */
305 310 "delete_all_entries", OPT_ABSENT, delete_all_entries, 0, /* PVT */
306 311 "update_entry", OPT_REQ, update_entry, 0, /* menu */
307 312 "update_temp", OPT_OPTIONAL, update_temp, 0, /* reboot */
308 313 "upgrade", OPT_ABSENT, upgrade_menu, 0, /* menu */
309 314 "list_setting", OPT_OPTIONAL, list_setting, 1, /* menu */
310 315 "disable_hypervisor", OPT_ABSENT, cvt_to_metal, 0, /* menu */
311 316 "enable_hypervisor", OPT_ABSENT, cvt_to_hyper, 0, /* menu */
312 317 NULL, 0, NULL, 0 /* must be last */
313 318 };
314 319
315 320 /* Archive related sub commands */
316 321 static subcmd_defn_t arch_subcmds[] = {
317 322 "update", OPT_ABSENT, update_archive, 0, /* PUB */
318 323 "update_all", OPT_ABSENT, update_all, 0, /* PVT */
319 324 "list", OPT_OPTIONAL, list_archive, 1, /* PUB */
320 325 NULL, 0, NULL, 0 /* must be last */
321 326 };
322 327
323 328 /* Install related sub commands */
324 329 static subcmd_defn_t inst_subcmds[] = {
325 330 "install_bootloader", OPT_ABSENT, install_bootloader, 0, /* PUB */
326 331 NULL, 0, NULL, 0 /* must be last */
327 332 };
328 333
329 334 #define build_path(buf, len, root, prefix, suffix) \
330 335 snprintf((buf), (len), "%s%s%s%s%s", (root), (prefix), get_machine(), \
331 336 is_flag_on(IS_SPARC_TARGET) ? "" : "/amd64", (suffix))
332 337
333 338 /*
334 339 * Directory specific flags:
335 340 * NEED_UPDATE : the specified archive needs to be updated
336 341 * NO_EXTEND : don't extend the specified archive, but recreate it
337 342 */
338 343 #define NEED_UPDATE 0x00000001
339 344 #define NO_EXTEND 0x00000002
340 345
341 346 #define set_dir_flag(f) (walk_arg.dirinfo.flags |= (f))
342 347 #define unset_dir_flag(f) (walk_arg.dirinfo.flags &= ~(f))
343 348 #define is_dir_flag_on(f) (walk_arg.dirinfo.flags & (f) ? 1 : 0)
344 349
345 350 #define get_cachedir() (walk_arg.dirinfo.cdir_path)
346 351 #define get_updatedir() (walk_arg.dirinfo.update_path)
347 352 #define get_count() (walk_arg.dirinfo.count)
348 353 #define has_cachedir() (walk_arg.dirinfo.has_dir)
349 354 #define set_dir_present() (walk_arg.dirinfo.has_dir = 1)
350 355
351 356 /*
352 357 * dirinfo_t (specific cache directory information):
353 358 * cdir_path: path to the archive cache directory
354 359 * update_path: path to the update directory (contains the files that will be
355 360 * used to extend the archive)
356 361 * has_dir: the specified cache directory is active
357 362 * count: the number of files to update
358 363 * flags: directory specific flags
359 364 */
360 365 typedef struct _dirinfo {
361 366 char cdir_path[PATH_MAX];
362 367 char update_path[PATH_MAX];
363 368 int has_dir;
364 369 int count;
365 370 int flags;
366 371 } dirinfo_t;
367 372
368 373 /*
369 374 * Update flags:
370 375 * NEED_CACHE_DIR : cache directory is missing and needs to be created
371 376 * IS_SPARC_TARGET : the target mountpoint is a SPARC environment
372 377 * UPDATE_ERROR : an error occourred while traversing the list of files
373 378 * RDONLY_FSCHK : the target filesystem is read-only
374 379 * RAMDSK_FSCHK : the target filesystem is on a ramdisk
375 380 */
376 381 #define NEED_CACHE_DIR 0x00000001
377 382 #define IS_SPARC_TARGET 0x00000002
378 383 #define UPDATE_ERROR 0x00000004
379 384 #define RDONLY_FSCHK 0x00000008
380 385 #define INVALIDATE_CACHE 0x00000010
381 386
382 387 #define is_flag_on(flag) (walk_arg.update_flags & flag ? 1 : 0)
383 388 #define set_flag(flag) (walk_arg.update_flags |= flag)
384 389 #define unset_flag(flag) (walk_arg.update_flags &= ~flag)
385 390
386 391 /*
387 392 * struct walk_arg :
388 393 * update_flags: flags related to the current updating process
389 394 * new_nvlp/old_nvlp: new and old list of archive-files / attributes pairs
390 395 * sparcfile: list of file paths for mkisofs -path-list (SPARC only)
391 396 */
392 397 static struct {
393 398 int update_flags;
394 399 nvlist_t *new_nvlp;
395 400 nvlist_t *old_nvlp;
396 401 FILE *sparcfile;
397 402 dirinfo_t dirinfo;
398 403 } walk_arg;
399 404
400 405 struct safefile {
401 406 char *name;
402 407 struct safefile *next;
403 408 };
404 409
405 410 static struct safefile *safefiles = NULL;
406 411
407 412 /*
408 413 * svc:/system/filesystem/usr:default service checks for this file and
409 414 * does a boot archive update and then reboot the system.
410 415 */
411 416 #define NEED_UPDATE_FILE "/etc/svc/volatile/boot_archive_needs_update"
412 417
413 418 /*
414 419 * svc:/system/boot-archive-update:default checks for this file and
415 420 * updates the boot archive.
416 421 */
417 422 #define NEED_UPDATE_SAFE_FILE "/etc/svc/volatile/boot_archive_safefile_update"
418 423
419 424 /* Thanks growisofs */
420 425 #define CD_BLOCK ((off64_t)2048)
421 426 #define VOLDESC_OFF 16
422 427 #define DVD_BLOCK (32*1024)
423 428 #define MAX_IVDs 16
424 429
425 430 struct iso_pdesc {
426 431 unsigned char type [1];
427 432 unsigned char id [5];
428 433 unsigned char void1 [80-5-1];
429 434 unsigned char volume_space_size [8];
430 435 unsigned char void2 [2048-80-8];
431 436 };
432 437
433 438 /*
434 439 * COUNT_MAX: maximum number of changed files to justify a multisession update
435 440 * BA_SIZE_MAX: maximum size of the boot_archive to justify a multisession
436 441 * update
437 442 */
438 443 #define COUNT_MAX 50
439 444 #define BA_SIZE_MAX (50 * 1024 * 1024)
440 445
441 446 #define bam_nowrite() (bam_check || bam_smf_check)
442 447
443 448 static int sync_menu = 1; /* whether we need to sync the BE menus */
444 449
445 450 static void
446 451 usage(void)
447 452 {
448 453 (void) fprintf(stderr, "USAGE:\n");
449 454
450 455 /* archive usage */
451 456 (void) fprintf(stderr,
452 457 "\t%s update-archive [-vnf] [-R altroot [-p platform]] "
453 458 "[-F format]\n", prog);
454 459 (void) fprintf(stderr,
455 460 "\t%s list-archive [-R altroot [-p platform]]\n", prog);
456 461 #if defined(_OBP)
457 462 (void) fprintf(stderr,
458 463 "\t%s install-bootloader [-fv] [-R altroot] [-P pool]\n", prog);
459 464 #else
460 465 (void) fprintf(stderr,
461 466 "\t%s install-bootloader [-Mfv] [-R altroot] [-P pool]\n", prog);
462 467 #endif
463 468 #if !defined(_OBP)
464 469 /* x86 only */
465 470 (void) fprintf(stderr, "\t%s set-menu [-R altroot] key=value\n", prog);
466 471 (void) fprintf(stderr, "\t%s list-menu [-R altroot]\n", prog);
467 472 #endif
468 473 }
469 474
470 475 /*
471 476 * Best effort attempt to restore the $HOME value.
472 477 */
473 478 static void
474 479 restore_env()
475 480 {
476 481 char home_env[PATH_MAX];
477 482
478 483 if (bam_home_env) {
479 484 (void) snprintf(home_env, sizeof (home_env), "HOME=%s",
480 485 bam_home_env);
481 486 (void) putenv(home_env);
482 487 }
483 488 }
484 489
485 490
486 491 #define SLEEP_TIME 5
487 492 #define MAX_TRIES 4
488 493
489 494 /*
490 495 * Sanitize the environment in which bootadm will execute its sub-processes
491 496 * (ex. mkisofs). This is done to prevent those processes from attempting
492 497 * to access files (ex. .mkisofsrc) or stat paths that might be on NFS
493 498 * or, potentially, insecure.
494 499 */
495 500 static void
496 501 sanitize_env()
497 502 {
498 503 int stry = 0;
499 504
500 505 /* don't depend on caller umask */
501 506 (void) umask(0022);
502 507
503 508 /* move away from a potential unsafe current working directory */
504 509 while (chdir("/") == -1) {
505 510 if (errno != EINTR) {
506 511 bam_print("WARNING: unable to chdir to /");
507 512 break;
508 513 }
509 514 }
510 515
511 516 bam_home_env = getenv("HOME");
512 517 while (bam_home_env != NULL && putenv("HOME=/") == -1) {
513 518 if (errno == ENOMEM) {
514 519 /* retry no more than MAX_TRIES times */
515 520 if (++stry > MAX_TRIES) {
516 521 bam_print("WARNING: unable to recover from "
517 522 "system memory pressure... aborting \n");
518 523 bam_exit(EXIT_FAILURE);
519 524 }
520 525 /* memory is tight, try to sleep */
521 526 bam_print("Attempting to recover from memory pressure: "
522 527 "sleeping for %d seconds\n", SLEEP_TIME * stry);
523 528 (void) sleep(SLEEP_TIME * stry);
524 529 } else {
525 530 bam_print("WARNING: unable to sanitize HOME\n");
526 531 }
527 532 }
528 533 }
529 534
530 535 int
531 536 main(int argc, char *argv[])
532 537 {
533 538 error_t ret = BAM_SUCCESS;
534 539
535 540 (void) setlocale(LC_ALL, "");
536 541 (void) textdomain(TEXT_DOMAIN);
537 542
538 543 if ((prog = strrchr(argv[0], '/')) == NULL) {
539 544 prog = argv[0];
540 545 } else {
541 546 prog++;
542 547 }
543 548
544 549 INJECT_ERROR1("ASSERT_ON", assert(0))
545 550
546 551 sanitize_env();
547 552
548 553 parse_args(argc, argv);
549 554
550 555 switch (bam_cmd) {
551 556 case BAM_MENU:
552 557 if (is_grub(bam_alt_root ? bam_root : "/")) {
553 558 ret = bam_menu(bam_subcmd, bam_opt,
554 559 bam_argc, bam_argv);
555 560 } else {
556 561 ret = bam_loader_menu(bam_subcmd, bam_opt,
557 562 bam_argc, bam_argv);
558 563 }
559 564 break;
560 565 case BAM_ARCHIVE:
561 566 ret = bam_archive(bam_subcmd, bam_opt);
562 567 break;
563 568 case BAM_INSTALL:
564 569 ret = bam_install(bam_subcmd, bam_opt);
565 570 break;
566 571 default:
567 572 usage();
568 573 bam_exit(1);
569 574 }
570 575
571 576 if (ret != BAM_SUCCESS)
572 577 bam_exit((ret == BAM_NOCHANGE) ? 2 : 1);
573 578
574 579 bam_unlock();
575 580 return (0);
576 581 }
577 582
578 583 /*
579 584 * Equivalence of public and internal commands:
580 585 * update-archive -- -a update
581 586 * list-archive -- -a list
582 587 * set-menu -- -m set_option
583 588 * list-menu -- -m list_entry
584 589 * update-menu -- -m update_entry
585 590 * install-bootloader -- -i install_bootloader
586 591 */
587 592 static struct cmd_map {
588 593 char *bam_cmdname;
589 594 int bam_cmd;
590 595 char *bam_subcmd;
591 596 } cmd_map[] = {
592 597 { "update-archive", BAM_ARCHIVE, "update"},
593 598 { "list-archive", BAM_ARCHIVE, "list"},
594 599 { "set-menu", BAM_MENU, "set_option"},
595 600 { "list-menu", BAM_MENU, "list_entry"},
596 601 { "update-menu", BAM_MENU, "update_entry"},
597 602 { "install-bootloader", BAM_INSTALL, "install_bootloader"},
598 603 { NULL, 0, NULL}
599 604 };
600 605
601 606 /*
602 607 * Commands syntax published in bootadm(1M) are parsed here
603 608 */
604 609 static void
605 610 parse_args(int argc, char *argv[])
606 611 {
607 612 struct cmd_map *cmp = cmd_map;
608 613
609 614 /* command conforming to the final spec */
610 615 if (argc > 1 && argv[1][0] != '-') {
611 616 /*
612 617 * Map commands to internal table.
613 618 */
614 619 while (cmp->bam_cmdname) {
615 620 if (strcmp(argv[1], cmp->bam_cmdname) == 0) {
616 621 bam_cmd = cmp->bam_cmd;
617 622 bam_subcmd = cmp->bam_subcmd;
618 623 break;
619 624 }
620 625 cmp++;
621 626 }
622 627 if (cmp->bam_cmdname == NULL) {
623 628 usage();
624 629 bam_exit(1);
625 630 }
626 631 argc--;
627 632 argv++;
628 633 }
629 634
630 635 parse_args_internal(argc, argv);
631 636 }
632 637
633 638 /*
634 639 * A combination of public and private commands are parsed here.
635 640 * The internal syntax and the corresponding functionality are:
636 641 * -a update -- update-archive
637 642 * -a list -- list-archive
638 643 * -a update_all -- (reboot to sync all mnted OS archive)
639 644 * -i install_bootloader -- install-bootloader
640 645 * -m update_entry -- update-menu
641 646 * -m list_entry -- list-menu
642 647 * -m update_temp -- (reboot -- [boot-args])
643 648 * -m delete_all_entries -- (called from install)
644 649 * -m enable_hypervisor [args] -- cvt_to_hyper
645 650 * -m disable_hypervisor -- cvt_to_metal
646 651 * -m list_setting [entry] [value] -- list_setting
647 652 *
648 653 * A set of private flags is there too:
649 654 * -Q -- purge the cache directories and rebuild them
650 655 * -e -- use the (faster) archive update approach (used by
651 656 * reboot)
652 657 * -L -- skip locking
653 658 */
654 659 static void
655 660 parse_args_internal(int argc, char *argv[])
656 661 {
657 662 int c, i, error;
658 663 extern char *optarg;
659 664 extern int optind, opterr;
660 665 #if defined(_OBP)
661 666 const char *optstring = "a:d:fF:i:m:no:veQCLR:p:P:XZ";
662 667 #else
663 668 const char *optstring = "a:d:fF:i:m:no:veQCMLR:p:P:XZ";
664 669 #endif
665 670
666 671 /* Suppress error message from getopt */
667 672 opterr = 0;
668 673
669 674 error = 0;
670 675 while ((c = getopt(argc, argv, optstring)) != -1) {
671 676 switch (c) {
672 677 case 'a':
673 678 if (bam_cmd) {
674 679 error = 1;
675 680 bam_error(
676 681 _("multiple commands specified: -%c\n"), c);
677 682 }
678 683 bam_cmd = BAM_ARCHIVE;
679 684 bam_subcmd = optarg;
680 685 break;
681 686 case 'd':
682 687 if (bam_debug) {
683 688 error = 1;
684 689 bam_error(
685 690 _("duplicate options specified: -%c\n"), c);
686 691 }
687 692 bam_debug = s_strtol(optarg);
688 693 break;
689 694 case 'f':
690 695 bam_force = 1;
691 696 break;
692 697 case 'F':
693 698 if (bam_format != BAM_FORMAT_UNSET) {
694 699 error = 1;
695 700 bam_error(
696 701 _("multiple formats specified: -%c\n"), c);
697 702 }
698 703 for (i = 0; bam_formats[i] != NULL; i++) {
699 704 if (strcmp(bam_formats[i], optarg) == 0) {
700 705 bam_format = i;
701 706 break;
702 707 }
703 708 }
704 709 if (bam_format == BAM_FORMAT_UNSET) {
705 710 error = 1;
706 711 bam_error(
707 712 _("unknown format specified: -%c %s\n"),
708 713 c, optarg);
709 714 }
710 715 break;
711 716 case 'Q':
712 717 bam_purge = 1;
713 718 break;
714 719 case 'L':
715 720 bam_skip_lock = 1;
716 721 break;
717 722 case 'i':
718 723 if (bam_cmd) {
719 724 error = 1;
720 725 bam_error(
721 726 _("multiple commands specified: -%c\n"), c);
722 727 }
723 728 bam_cmd = BAM_INSTALL;
724 729 bam_subcmd = optarg;
725 730 break;
726 731 case 'm':
727 732 if (bam_cmd) {
728 733 error = 1;
729 734 bam_error(
730 735 _("multiple commands specified: -%c\n"), c);
731 736 }
732 737 bam_cmd = BAM_MENU;
733 738 bam_subcmd = optarg;
734 739 break;
735 740 #if !defined(_OBP)
736 741 case 'M':
737 742 bam_mbr = 1;
738 743 break;
739 744 #endif
740 745 case 'n':
741 746 bam_check = 1;
742 747 /*
743 748 * We save the original value of bam_check. The new
744 749 * approach in case of a read-only filesystem is to
745 750 * behave as a check, so we need a way to restore the
746 751 * original value after the evaluation of the read-only
747 752 * filesystem has been done.
748 753 * Even if we don't allow at the moment a check with
749 754 * update_all, this approach is more robust than
750 755 * simply resetting bam_check to zero.
751 756 */
752 757 bam_saved_check = 1;
753 758 break;
754 759 case 'o':
755 760 if (bam_opt) {
756 761 error = 1;
757 762 bam_error(
758 763 _("duplicate options specified: -%c\n"), c);
759 764 }
760 765 bam_opt = optarg;
761 766 break;
762 767 case 'v':
763 768 bam_verbose = 1;
764 769 break;
765 770 case 'C':
766 771 bam_smf_check = 1;
767 772 break;
768 773 case 'P':
769 774 if (bam_pool != NULL) {
770 775 error = 1;
771 776 bam_error(
772 777 _("duplicate options specified: -%c\n"), c);
773 778 }
774 779 bam_pool = optarg;
775 780 break;
776 781 case 'R':
777 782 if (bam_root) {
778 783 error = 1;
779 784 bam_error(
780 785 _("duplicate options specified: -%c\n"), c);
781 786 break;
782 787 } else if (realpath(optarg, rootbuf) == NULL) {
783 788 error = 1;
784 789 bam_error(_("cannot resolve path %s: %s\n"),
785 790 optarg, strerror(errno));
786 791 break;
787 792 }
788 793 bam_alt_root = 1;
789 794 bam_root = rootbuf;
790 795 bam_rootlen = strlen(rootbuf);
791 796 break;
792 797 case 'p':
793 798 bam_alt_platform = 1;
794 799 bam_platform = optarg;
795 800 if ((strcmp(bam_platform, "i86pc") != 0) &&
796 801 (strcmp(bam_platform, "sun4u") != 0) &&
797 802 (strcmp(bam_platform, "sun4v") != 0)) {
798 803 error = 1;
799 804 bam_error(_("invalid platform %s - must be "
800 805 "one of sun4u, sun4v or i86pc\n"),
801 806 bam_platform);
802 807 }
803 808 break;
804 809 case 'X':
805 810 bam_is_hv = BAM_HV_PRESENT;
806 811 break;
807 812 case 'Z':
808 813 bam_zfs = 1;
809 814 break;
810 815 case 'e':
811 816 bam_extend = 1;
812 817 break;
813 818 case '?':
814 819 error = 1;
815 820 bam_error(_("invalid option or missing option "
816 821 "argument: -%c\n"), optopt);
817 822 break;
818 823 default :
819 824 error = 1;
820 825 bam_error(_("invalid option or missing option "
821 826 "argument: -%c\n"), c);
822 827 break;
823 828 }
824 829 }
825 830
826 831 /*
827 832 * An alternate platform requires an alternate root
828 833 */
829 834 if (bam_alt_platform && bam_alt_root == 0) {
830 835 usage();
831 836 bam_exit(0);
832 837 }
833 838
834 839 /*
835 840 * A command option must be specfied
836 841 */
837 842 if (!bam_cmd) {
838 843 if (bam_opt && strcmp(bam_opt, "all") == 0) {
839 844 usage();
840 845 bam_exit(0);
841 846 }
842 847 bam_error(_("a command option must be specified\n"));
843 848 error = 1;
844 849 }
845 850
846 851 if (error) {
847 852 usage();
848 853 bam_exit(1);
849 854 }
850 855
851 856 if (optind > argc) {
852 857 bam_error(_("Internal error: %s\n"), "parse_args");
853 858 bam_exit(1);
854 859 } else if (optind < argc) {
855 860 bam_argv = &argv[optind];
856 861 bam_argc = argc - optind;
857 862 }
858 863
859 864 /*
860 865 * mbr and pool are options for install_bootloader
861 866 */
862 867 if (bam_cmd != BAM_INSTALL && (bam_mbr || bam_pool != NULL)) {
863 868 usage();
864 869 bam_exit(0);
865 870 }
866 871
867 872 /*
868 873 * -n implies verbose mode
869 874 */
870 875 if (bam_check)
871 876 bam_verbose = 1;
872 877 }
873 878
874 879 error_t
875 880 check_subcmd_and_options(
876 881 char *subcmd,
877 882 char *opt,
878 883 subcmd_defn_t *table,
879 884 error_t (**fp)())
880 885 {
881 886 int i;
882 887
883 888 if (subcmd == NULL) {
884 889 bam_error(_("this command requires a sub-command\n"));
885 890 return (BAM_ERROR);
886 891 }
887 892
888 893 if (strcmp(subcmd, "set_option") == 0) {
889 894 if (bam_argc == 0 || bam_argv == NULL || bam_argv[0] == NULL) {
890 895 bam_error(_("missing argument for sub-command\n"));
891 896 usage();
892 897 return (BAM_ERROR);
893 898 } else if (bam_argc > 1 || bam_argv[1] != NULL) {
894 899 bam_error(_("invalid trailing arguments\n"));
895 900 usage();
896 901 return (BAM_ERROR);
897 902 }
898 903 } else if (strcmp(subcmd, "update_all") == 0) {
899 904 /*
900 905 * The only option we accept for the "update_all"
901 906 * subcmd is "fastboot".
902 907 */
903 908 if (bam_argc > 1 || (bam_argc == 1 &&
904 909 strcmp(bam_argv[0], "fastboot") != 0)) {
905 910 bam_error(_("invalid trailing arguments\n"));
906 911 usage();
907 912 return (BAM_ERROR);
908 913 }
909 914 if (bam_argc == 1)
910 915 sync_menu = 0;
911 916 } else if (((strcmp(subcmd, "enable_hypervisor") != 0) &&
912 917 (strcmp(subcmd, "list_setting") != 0)) && (bam_argc || bam_argv)) {
913 918 /*
914 919 * Of the remaining subcommands, only "enable_hypervisor" and
915 920 * "list_setting" take trailing arguments.
916 921 */
917 922 bam_error(_("invalid trailing arguments\n"));
918 923 usage();
919 924 return (BAM_ERROR);
920 925 }
921 926
922 927 if (bam_root == NULL) {
923 928 bam_root = rootbuf;
924 929 bam_rootlen = 1;
925 930 }
926 931
927 932 /* verify that subcmd is valid */
928 933 for (i = 0; table[i].subcmd != NULL; i++) {
929 934 if (strcmp(table[i].subcmd, subcmd) == 0)
930 935 break;
931 936 }
932 937
933 938 if (table[i].subcmd == NULL) {
934 939 bam_error(_("invalid sub-command specified: %s\n"), subcmd);
935 940 return (BAM_ERROR);
936 941 }
937 942
938 943 if (table[i].unpriv == 0 && geteuid() != 0) {
939 944 bam_error(_("you must be root to run this command\n"));
940 945 return (BAM_ERROR);
941 946 }
942 947
943 948 /*
944 949 * Currently only privileged commands need a lock
945 950 */
946 951 if (table[i].unpriv == 0)
947 952 bam_lock();
948 953
949 954 /* subcmd verifies that opt is appropriate */
950 955 if (table[i].option != OPT_OPTIONAL) {
951 956 if ((table[i].option == OPT_REQ) ^ (opt != NULL)) {
952 957 if (opt)
953 958 bam_error(_("this sub-command (%s) does not "
954 959 "take options\n"), subcmd);
955 960 else
956 961 bam_error(_("an option is required for this "
957 962 "sub-command: %s\n"), subcmd);
958 963 return (BAM_ERROR);
959 964 }
960 965 }
961 966
962 967 *fp = table[i].handler;
963 968
964 969 return (BAM_SUCCESS);
965 970 }
966 971
967 972 /*
968 973 * NOTE: A single "/" is also considered a trailing slash and will
969 974 * be deleted.
970 975 */
971 976 void
972 977 elide_trailing_slash(const char *src, char *dst, size_t dstsize)
973 978 {
974 979 size_t dstlen;
975 980
976 981 assert(src);
977 982 assert(dst);
978 983
979 984 (void) strlcpy(dst, src, dstsize);
980 985
981 986 dstlen = strlen(dst);
982 987 if (dst[dstlen - 1] == '/') {
983 988 dst[dstlen - 1] = '\0';
984 989 }
985 990 }
986 991
987 992 static int
988 993 is_safe_exec(char *path)
989 994 {
990 995 struct stat sb;
991 996
992 997 if (lstat(path, &sb) != 0) {
993 998 bam_error(_("stat of file failed: %s: %s\n"), path,
994 999 strerror(errno));
995 1000 return (BAM_ERROR);
996 1001 }
997 1002
998 1003 if (!S_ISREG(sb.st_mode)) {
999 1004 bam_error(_("%s is not a regular file, skipping\n"), path);
1000 1005 return (BAM_ERROR);
1001 1006 }
1002 1007
1003 1008 if (sb.st_uid != getuid()) {
1004 1009 bam_error(_("%s is not owned by %d, skipping\n"),
1005 1010 path, getuid());
1006 1011 return (BAM_ERROR);
1007 1012 }
1008 1013
1009 1014 if (sb.st_mode & S_IWOTH || sb.st_mode & S_IWGRP) {
1010 1015 bam_error(_("%s is others or group writable, skipping\n"),
1011 1016 path);
1012 1017 return (BAM_ERROR);
1013 1018 }
1014 1019
1015 1020 return (BAM_SUCCESS);
1016 1021 }
1017 1022
1018 1023 static error_t
1019 1024 list_setting(menu_t *mp, char *which, char *setting)
1020 1025 {
1021 1026 line_t *lp;
1022 1027 entry_t *ent;
1023 1028
1024 1029 char *p = which;
1025 1030 int entry;
1026 1031
1027 1032 int found;
1028 1033
1029 1034 assert(which);
1030 1035 assert(setting);
1031 1036
1032 1037 if (*which != NULL) {
1033 1038 /*
1034 1039 * If "which" is not a number, assume it's a setting we want
1035 1040 * to look for and so set up the routine to look for "which"
1036 1041 * in the default entry.
1037 1042 */
1038 1043 while (*p != NULL)
1039 1044 if (!(isdigit((int)*p++))) {
1040 1045 setting = which;
1041 1046 which = mp->curdefault->arg;
1042 1047 break;
1043 1048 }
1044 1049 } else {
1045 1050 which = mp->curdefault->arg;
1046 1051 }
1047 1052
1048 1053 entry = atoi(which);
1049 1054
1050 1055 for (ent = mp->entries; ((ent != NULL) && (ent->entryNum != entry));
1051 1056 ent = ent->next)
1052 1057 ;
1053 1058
1054 1059 if (!ent) {
1055 1060 bam_error(_("no matching entry found\n"));
1056 1061 return (BAM_ERROR);
1057 1062 }
1058 1063
1059 1064 found = (*setting == NULL);
1060 1065
1061 1066 for (lp = ent->start; lp != NULL; lp = lp->next) {
1062 1067 if ((*setting == NULL) && (lp->flags != BAM_COMMENT))
1063 1068 bam_print("%s\n", lp->line);
1064 1069 else if (lp->cmd != NULL && strcmp(setting, lp->cmd) == 0) {
1065 1070 bam_print("%s\n", lp->arg);
1066 1071 found = 1;
1067 1072 }
1068 1073
1069 1074 if (lp == ent->end)
1070 1075 break;
1071 1076 }
1072 1077
1073 1078 if (!found) {
1074 1079 bam_error(_("no matching entry found\n"));
1075 1080 return (BAM_ERROR);
1076 1081 }
1077 1082
1078 1083 return (BAM_SUCCESS);
1079 1084 }
1080 1085
1081 1086 static error_t
1082 1087 install_bootloader(void)
1083 1088 {
1084 1089 nvlist_t *nvl;
1085 1090 uint16_t flags = 0;
1086 1091 int found = 0;
1087 1092 struct extmnttab mnt;
1088 1093 struct stat statbuf = {0};
1089 1094 be_node_list_t *be_nodes, *node;
1090 1095 FILE *fp;
1091 1096 char *root_ds = NULL;
1092 1097 int ret = BAM_ERROR;
1093 1098
1094 1099 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
1095 1100 bam_error(_("out of memory\n"));
1096 1101 return (ret);
1097 1102 }
1098 1103
1099 1104 /*
1100 1105 * if bam_alt_root is set, the stage files are used from alt root.
1101 1106 * if pool is set, the target devices are pool devices, stage files
1102 1107 * are read from pool bootfs unless alt root is set.
1103 1108 *
1104 1109 * use arguments as targets, stage files are from alt or current root
1105 1110 * if no arguments and no pool, install on current boot pool.
1106 1111 */
1107 1112
1108 1113 if (bam_alt_root) {
1109 1114 if (stat(bam_root, &statbuf) != 0) {
1110 1115 bam_error(_("stat of file failed: %s: %s\n"), bam_root,
1111 1116 strerror(errno));
1112 1117 goto done;
1113 1118 }
1114 1119 if ((fp = fopen(MNTTAB, "r")) == NULL) {
1115 1120 bam_error(_("failed to open file: %s: %s\n"),
1116 1121 MNTTAB, strerror(errno));
1117 1122 goto done;
1118 1123 }
1119 1124 resetmnttab(fp);
1120 1125 while (getextmntent(fp, &mnt, sizeof (mnt)) == 0) {
1121 1126 if (mnt.mnt_major == major(statbuf.st_dev) &&
1122 1127 mnt.mnt_minor == minor(statbuf.st_dev)) {
1123 1128 found = 1;
1124 1129 root_ds = strdup(mnt.mnt_special);
1125 1130 break;
1126 1131 }
1127 1132 }
1128 1133 (void) fclose(fp);
1129 1134
1130 1135 if (found == 0) {
1131 1136 bam_error(_("alternate root %s not in mnttab\n"),
1132 1137 bam_root);
1133 1138 goto done;
1134 1139 }
1135 1140 if (root_ds == NULL) {
1136 1141 bam_error(_("out of memory\n"));
1137 1142 goto done;
1138 1143 }
1139 1144
1140 1145 if (be_list(NULL, &be_nodes, BE_LIST_DEFAULT) != BE_SUCCESS) {
1141 1146 bam_error(_("No BE's found\n"));
1142 1147 goto done;
1143 1148 }
1144 1149 for (node = be_nodes; node != NULL; node = node->be_next_node)
1145 1150 if (strcmp(root_ds, node->be_root_ds) == 0)
1146 1151 break;
1147 1152
1148 1153 if (node == NULL)
1149 1154 bam_error(_("BE (%s) does not exist\n"), root_ds);
1150 1155
1151 1156 free(root_ds);
1152 1157 root_ds = NULL;
1153 1158 if (node == NULL) {
1154 1159 be_free_list(be_nodes);
1155 1160 goto done;
1156 1161 }
1157 1162 ret = nvlist_add_string(nvl, BE_ATTR_ORIG_BE_NAME,
1158 1163 node->be_node_name);
1159 1164 ret |= nvlist_add_string(nvl, BE_ATTR_ORIG_BE_ROOT,
1160 1165 node->be_root_ds);
1161 1166 be_free_list(be_nodes);
1162 1167 if (ret != 0) {
1163 1168 ret = BAM_ERROR;
1164 1169 goto done;
1165 1170 }
1166 1171 }
1167 1172
1168 1173 if (bam_force)
1169 1174 flags |= BE_INSTALLBOOT_FLAG_FORCE;
1170 1175 if (bam_mbr)
1171 1176 flags |= BE_INSTALLBOOT_FLAG_MBR;
1172 1177 if (bam_verbose)
1173 1178 flags |= BE_INSTALLBOOT_FLAG_VERBOSE;
1174 1179
1175 1180 if (nvlist_add_uint16(nvl, BE_ATTR_INSTALL_FLAGS, flags) != 0) {
1176 1181 bam_error(_("out of memory\n"));
1177 1182 ret = BAM_ERROR;
1178 1183 goto done;
1179 1184 }
1180 1185
1181 1186 /*
1182 1187 * if altroot was set, we got be name and be root, only need
1183 1188 * to set pool name as target.
1184 1189 * if no altroot, need to find be name and root from pool.
1185 1190 */
1186 1191 if (bam_pool != NULL) {
1187 1192 ret = nvlist_add_string(nvl, BE_ATTR_ORIG_BE_POOL, bam_pool);
1188 1193 if (ret != 0) {
1189 1194 ret = BAM_ERROR;
1190 1195 goto done;
1191 1196 }
1192 1197 if (found) {
1193 1198 ret = be_installboot(nvl);
1194 1199 if (ret != 0)
1195 1200 ret = BAM_ERROR;
1196 1201 goto done;
1197 1202 }
1198 1203 }
1199 1204
1200 1205 if (be_list(NULL, &be_nodes, BE_LIST_DEFAULT) != BE_SUCCESS) {
1201 1206 bam_error(_("No BE's found\n"));
1202 1207 ret = BAM_ERROR;
1203 1208 goto done;
1204 1209 }
1205 1210
1206 1211 if (bam_pool != NULL) {
1207 1212 /*
1208 1213 * find active be_node in bam_pool
1209 1214 */
1210 1215 for (node = be_nodes; node != NULL; node = node->be_next_node) {
1211 1216 if (strcmp(bam_pool, node->be_rpool) != 0)
1212 1217 continue;
1213 1218 if (node->be_active_on_boot)
1214 1219 break;
1215 1220 }
1216 1221 if (node == NULL) {
1217 1222 bam_error(_("No active BE in %s\n"), bam_pool);
1218 1223 be_free_list(be_nodes);
1219 1224 ret = BAM_ERROR;
1220 1225 goto done;
1221 1226 }
1222 1227 ret = nvlist_add_string(nvl, BE_ATTR_ORIG_BE_NAME,
1223 1228 node->be_node_name);
1224 1229 ret |= nvlist_add_string(nvl, BE_ATTR_ORIG_BE_ROOT,
1225 1230 node->be_root_ds);
1226 1231 be_free_list(be_nodes);
1227 1232 if (ret != 0) {
1228 1233 ret = BAM_ERROR;
1229 1234 goto done;
1230 1235 }
1231 1236 ret = be_installboot(nvl);
1232 1237 if (ret != 0)
1233 1238 ret = BAM_ERROR;
1234 1239 goto done;
1235 1240 }
1236 1241
1237 1242 /*
1238 1243 * get dataset for "/" and fill up the args.
1239 1244 */
1240 1245 if ((fp = fopen(MNTTAB, "r")) == NULL) {
1241 1246 bam_error(_("failed to open file: %s: %s\n"),
1242 1247 MNTTAB, strerror(errno));
1243 1248 ret = BAM_ERROR;
1244 1249 be_free_list(be_nodes);
1245 1250 goto done;
1246 1251 }
1247 1252 resetmnttab(fp);
1248 1253 found = 0;
1249 1254 while (getextmntent(fp, &mnt, sizeof (mnt)) == 0) {
1250 1255 if (strcmp(mnt.mnt_mountp, "/") == 0) {
1251 1256 found = 1;
1252 1257 root_ds = strdup(mnt.mnt_special);
1253 1258 break;
1254 1259 }
1255 1260 }
1256 1261 (void) fclose(fp);
1257 1262
1258 1263 if (found == 0) {
1259 1264 bam_error(_("alternate root %s not in mnttab\n"), "/");
1260 1265 ret = BAM_ERROR;
1261 1266 be_free_list(be_nodes);
1262 1267 goto done;
1263 1268 }
1264 1269 if (root_ds == NULL) {
1265 1270 bam_error(_("out of memory\n"));
1266 1271 ret = BAM_ERROR;
1267 1272 be_free_list(be_nodes);
1268 1273 goto done;
1269 1274 }
1270 1275
1271 1276 for (node = be_nodes; node != NULL; node = node->be_next_node) {
1272 1277 if (strcmp(root_ds, node->be_root_ds) == 0)
1273 1278 break;
1274 1279 }
1275 1280
1276 1281 if (node == NULL) {
1277 1282 bam_error(_("No such BE: %s\n"), root_ds);
1278 1283 free(root_ds);
1279 1284 be_free_list(be_nodes);
1280 1285 ret = BAM_ERROR;
1281 1286 goto done;
1282 1287 }
1283 1288 free(root_ds);
1284 1289
1285 1290 ret = nvlist_add_string(nvl, BE_ATTR_ORIG_BE_NAME, node->be_node_name);
1286 1291 ret |= nvlist_add_string(nvl, BE_ATTR_ORIG_BE_ROOT, node->be_root_ds);
1287 1292 ret |= nvlist_add_string(nvl, BE_ATTR_ORIG_BE_POOL, node->be_rpool);
1288 1293 be_free_list(be_nodes);
1289 1294
1290 1295 if (ret != 0)
1291 1296 ret = BAM_ERROR;
1292 1297 else
1293 1298 ret = be_installboot(nvl) ? BAM_ERROR : 0;
1294 1299 done:
1295 1300 nvlist_free(nvl);
1296 1301
1297 1302 return (ret);
1298 1303 }
1299 1304
1300 1305 static error_t
1301 1306 bam_install(char *subcmd, char *opt)
1302 1307 {
1303 1308 error_t (*f)(void);
1304 1309
1305 1310 /*
1306 1311 * Check arguments
1307 1312 */
1308 1313 if (check_subcmd_and_options(subcmd, opt, inst_subcmds, &f) ==
1309 1314 BAM_ERROR)
1310 1315 return (BAM_ERROR);
1311 1316
1312 1317 return (f());
1313 1318 }
1314 1319
1315 1320 static error_t
1316 1321 bam_menu(char *subcmd, char *opt, int largc, char *largv[])
1317 1322 {
1318 1323 error_t ret;
1319 1324 char menu_path[PATH_MAX];
1320 1325 char clean_menu_root[PATH_MAX];
1321 1326 char path[PATH_MAX];
1322 1327 menu_t *menu;
1323 1328 char menu_root[PATH_MAX];
1324 1329 struct stat sb;
1325 1330 error_t (*f)(menu_t *mp, char *menu_path, char *opt);
1326 1331 char *special = NULL;
1327 1332 char *pool = NULL;
1328 1333 zfs_mnted_t zmnted;
1329 1334 char *zmntpt = NULL;
1330 1335 char *osdev;
1331 1336 char *osroot;
1332 1337 const char *fcn = "bam_menu()";
1333 1338
1334 1339 /*
1335 1340 * Menu sub-command only applies to GRUB (i.e. x86)
1336 1341 */
1337 1342 if (!is_grub(bam_alt_root ? bam_root : "/")) {
1338 1343 bam_error(_("not a GRUB 0.97 based Illumos instance. "
1339 1344 "Operation not supported\n"));
1340 1345 return (BAM_ERROR);
1341 1346 }
1342 1347
1343 1348 /*
1344 1349 * Check arguments
1345 1350 */
1346 1351 ret = check_subcmd_and_options(subcmd, opt, menu_subcmds, &f);
1347 1352 if (ret == BAM_ERROR) {
1348 1353 return (BAM_ERROR);
1349 1354 }
1350 1355
1351 1356 assert(bam_root);
1352 1357
1353 1358 (void) strlcpy(menu_root, bam_root, sizeof (menu_root));
1354 1359 osdev = osroot = NULL;
1355 1360
1356 1361 if (strcmp(subcmd, "update_entry") == 0) {
1357 1362 assert(opt);
1358 1363
1359 1364 osdev = strtok(opt, ",");
1360 1365 assert(osdev);
1361 1366 osroot = strtok(NULL, ",");
1362 1367 if (osroot) {
1363 1368 /* fixup bam_root so that it points at osroot */
1364 1369 if (realpath(osroot, rootbuf) == NULL) {
1365 1370 bam_error(_("cannot resolve path %s: %s\n"),
1366 1371 osroot, strerror(errno));
1367 1372 return (BAM_ERROR);
1368 1373 }
1369 1374 bam_alt_root = 1;
1370 1375 bam_root = rootbuf;
1371 1376 bam_rootlen = strlen(rootbuf);
1372 1377 }
1373 1378 }
1374 1379
1375 1380 /*
1376 1381 * We support menu on PCFS (under certain conditions), but
1377 1382 * not the OS root
1378 1383 */
1379 1384 if (is_pcfs(bam_root)) {
1380 1385 bam_error(_("root <%s> on PCFS is not supported\n"), bam_root);
1381 1386 return (BAM_ERROR);
1382 1387 }
1383 1388
1384 1389 if (stat(menu_root, &sb) == -1) {
1385 1390 bam_error(_("cannot find GRUB menu\n"));
1386 1391 return (BAM_ERROR);
1387 1392 }
1388 1393
1389 1394 BAM_DPRINTF(("%s: menu root is %s\n", fcn, menu_root));
1390 1395
1391 1396 /*
1392 1397 * We no longer use the GRUB slice file. If it exists, then
1393 1398 * the user is doing something that is unsupported (such as
1394 1399 * standard upgrading an old Live Upgrade BE). If that
1395 1400 * happens, mimic existing behavior i.e. pretend that it is
1396 1401 * not a BE. Emit a warning though.
1397 1402 */
1398 1403 if (bam_alt_root) {
1399 1404 (void) snprintf(path, sizeof (path), "%s%s", bam_root,
1400 1405 GRUB_slice);
1401 1406 } else {
1402 1407 (void) snprintf(path, sizeof (path), "%s", GRUB_slice);
1403 1408 }
1404 1409
1405 1410 if (bam_verbose && stat(path, &sb) == 0)
1406 1411 bam_error(_("unsupported GRUB slice file (%s) exists - "
1407 1412 "ignoring.\n"), path);
1408 1413
1409 1414 if (is_zfs(menu_root)) {
1410 1415 assert(strcmp(menu_root, bam_root) == 0);
1411 1416 special = get_special(menu_root);
1412 1417 INJECT_ERROR1("Z_MENU_GET_SPECIAL", special = NULL);
1413 1418 if (special == NULL) {
1414 1419 bam_error(_("cant find special file for "
1415 1420 "mount-point %s\n"), menu_root);
1416 1421 return (BAM_ERROR);
1417 1422 }
1418 1423 pool = strtok(special, "/");
1419 1424 INJECT_ERROR1("Z_MENU_GET_POOL", pool = NULL);
1420 1425 if (pool == NULL) {
1421 1426 free(special);
1422 1427 bam_error(_("cant find pool for mount-point %s\n"),
1423 1428 menu_root);
1424 1429 return (BAM_ERROR);
1425 1430 }
1426 1431 BAM_DPRINTF(("%s: derived pool=%s from special\n", fcn, pool));
1427 1432
1428 1433 zmntpt = mount_top_dataset(pool, &zmnted);
1429 1434 INJECT_ERROR1("Z_MENU_MOUNT_TOP_DATASET", zmntpt = NULL);
1430 1435 if (zmntpt == NULL) {
1431 1436 bam_error(_("cannot mount pool dataset for pool: %s\n"),
1432 1437 pool);
1433 1438 free(special);
1434 1439 return (BAM_ERROR);
1435 1440 }
1436 1441 BAM_DPRINTF(("%s: top dataset mountpoint=%s\n", fcn, zmntpt));
1437 1442
1438 1443 (void) strlcpy(menu_root, zmntpt, sizeof (menu_root));
1439 1444 BAM_DPRINTF(("%s: zfs menu_root=%s\n", fcn, menu_root));
1440 1445 }
1441 1446
1442 1447 elide_trailing_slash(menu_root, clean_menu_root,
1443 1448 sizeof (clean_menu_root));
1444 1449
1445 1450 BAM_DPRINTF(("%s: cleaned menu root is <%s>\n", fcn, clean_menu_root));
1446 1451
1447 1452 (void) strlcpy(menu_path, clean_menu_root, sizeof (menu_path));
1448 1453 (void) strlcat(menu_path, GRUB_MENU, sizeof (menu_path));
1449 1454
1450 1455 BAM_DPRINTF(("%s: menu path is: %s\n", fcn, menu_path));
1451 1456
1452 1457 /*
1453 1458 * If listing the menu, display the menu location
1454 1459 */
1455 1460 if (strcmp(subcmd, "list_entry") == 0)
1456 1461 bam_print(_("the location for the active GRUB menu is: %s\n"),
1457 1462 menu_path);
1458 1463
1459 1464 if ((menu = menu_read(menu_path)) == NULL) {
1460 1465 bam_error(_("cannot find GRUB menu file: %s\n"), menu_path);
1461 1466 free(special);
1462 1467
1463 1468 return (BAM_ERROR);
1464 1469 }
1465 1470
1466 1471 /*
1467 1472 * We already checked the following case in
1468 1473 * check_subcmd_and_suboptions() above. Complete the
1469 1474 * final step now.
1470 1475 */
1471 1476 if (strcmp(subcmd, "set_option") == 0) {
1472 1477 assert(largc == 1 && largv[0] && largv[1] == NULL);
1473 1478 opt = largv[0];
1474 1479 } else if ((strcmp(subcmd, "enable_hypervisor") != 0) &&
1475 1480 (strcmp(subcmd, "list_setting") != 0)) {
1476 1481 assert(largc == 0 && largv == NULL);
1477 1482 }
1478 1483
1479 1484 ret = get_boot_cap(bam_root);
1480 1485 if (ret != BAM_SUCCESS) {
1481 1486 BAM_DPRINTF(("%s: Failed to get boot capability\n", fcn));
1482 1487 goto out;
1483 1488 }
1484 1489
1485 1490 /*
1486 1491 * Once the sub-cmd handler has run
1487 1492 * only the line field is guaranteed to have valid values
1488 1493 */
1489 1494 if (strcmp(subcmd, "update_entry") == 0) {
1490 1495 ret = f(menu, menu_root, osdev);
1491 1496 } else if (strcmp(subcmd, "upgrade") == 0) {
1492 1497 ret = f(menu, bam_root, menu_root);
1493 1498 } else if (strcmp(subcmd, "list_entry") == 0) {
1494 1499 ret = f(menu, menu_path, opt);
1495 1500 } else if (strcmp(subcmd, "list_setting") == 0) {
1496 1501 ret = f(menu, ((largc > 0) ? largv[0] : ""),
1497 1502 ((largc > 1) ? largv[1] : ""));
1498 1503 } else if (strcmp(subcmd, "disable_hypervisor") == 0) {
1499 1504 if (is_sparc()) {
1500 1505 bam_error(_("%s operation unsupported on SPARC "
1501 1506 "machines\n"), subcmd);
1502 1507 ret = BAM_ERROR;
1503 1508 } else {
1504 1509 ret = f(menu, bam_root, NULL);
1505 1510 }
1506 1511 } else if (strcmp(subcmd, "enable_hypervisor") == 0) {
1507 1512 if (is_sparc()) {
1508 1513 bam_error(_("%s operation unsupported on SPARC "
1509 1514 "machines\n"), subcmd);
1510 1515 ret = BAM_ERROR;
1511 1516 } else {
1512 1517 char *extra_args = NULL;
1513 1518
1514 1519 /*
1515 1520 * Compress all arguments passed in the largv[] array
1516 1521 * into one string that can then be appended to the
1517 1522 * end of the kernel$ string the routine to enable the
1518 1523 * hypervisor will build.
1519 1524 *
1520 1525 * This allows the caller to supply arbitrary unparsed
1521 1526 * arguments, such as dom0 memory settings or APIC
1522 1527 * options.
1523 1528 *
1524 1529 * This concatenation will be done without ANY syntax
1525 1530 * checking whatsoever, so it's the responsibility of
1526 1531 * the caller to make sure the arguments are valid and
1527 1532 * do not duplicate arguments the conversion routines
1528 1533 * may create.
1529 1534 */
1530 1535 if (largc > 0) {
1531 1536 int extra_len, i;
1532 1537
1533 1538 for (extra_len = 0, i = 0; i < largc; i++)
1534 1539 extra_len += strlen(largv[i]);
1535 1540
1536 1541 /*
1537 1542 * Allocate space for argument strings,
1538 1543 * intervening spaces and terminating NULL.
1539 1544 */
1540 1545 extra_args = alloca(extra_len + largc);
1541 1546
1542 1547 (void) strcpy(extra_args, largv[0]);
1543 1548
1544 1549 for (i = 1; i < largc; i++) {
1545 1550 (void) strcat(extra_args, " ");
1546 1551 (void) strcat(extra_args, largv[i]);
1547 1552 }
1548 1553 }
1549 1554
1550 1555 ret = f(menu, bam_root, extra_args);
1551 1556 }
1552 1557 } else
1553 1558 ret = f(menu, NULL, opt);
1554 1559
1555 1560 if (ret == BAM_WRITE) {
1556 1561 BAM_DPRINTF(("%s: writing menu to clean-menu-root: <%s>\n",
1557 1562 fcn, clean_menu_root));
1558 1563 ret = menu_write(clean_menu_root, menu);
1559 1564 }
1560 1565
1561 1566 out:
1562 1567 INJECT_ERROR1("POOL_SET", pool = "/pooldata");
1563 1568 assert((is_zfs(menu_root)) ^ (pool == NULL));
1564 1569 if (pool) {
1565 1570 (void) umount_top_dataset(pool, zmnted, zmntpt);
1566 1571 free(special);
1567 1572 }
1568 1573 menu_free(menu);
1569 1574 return (ret);
1570 1575 }
1571 1576
1572 1577
1573 1578 static error_t
1574 1579 bam_archive(
1575 1580 char *subcmd,
1576 1581 char *opt)
1577 1582 {
1578 1583 error_t ret;
1579 1584 error_t (*f)(char *root, char *opt);
1580 1585 const char *fcn = "bam_archive()";
1581 1586
1582 1587 /*
1583 1588 * Add trailing / for archive subcommands
1584 1589 */
1585 1590 if (rootbuf[strlen(rootbuf) - 1] != '/')
1586 1591 (void) strcat(rootbuf, "/");
1587 1592 bam_rootlen = strlen(rootbuf);
1588 1593
1589 1594 /*
1590 1595 * Check arguments
1591 1596 */
1592 1597 ret = check_subcmd_and_options(subcmd, opt, arch_subcmds, &f);
1593 1598 if (ret != BAM_SUCCESS) {
1594 1599 return (BAM_ERROR);
1595 1600 }
1596 1601
1597 1602 ret = get_boot_cap(rootbuf);
1598 1603 if (ret != BAM_SUCCESS) {
1599 1604 BAM_DPRINTF(("%s: Failed to get boot capability\n", fcn));
1600 1605 return (ret);
1601 1606 }
1602 1607
1603 1608 /*
1604 1609 * Check archive not supported with update_all
1605 1610 * since it is awkward to display out-of-sync
1606 1611 * information for each BE.
1607 1612 */
1608 1613 if (bam_check && strcmp(subcmd, "update_all") == 0) {
1609 1614 bam_error(_("the check option is not supported with "
1610 1615 "subcmd: %s\n"), subcmd);
1611 1616 return (BAM_ERROR);
1612 1617 }
1613 1618
1614 1619 if (strcmp(subcmd, "update_all") == 0)
1615 1620 bam_update_all = 1;
1616 1621
1617 1622 #if !defined(_OBP)
1618 1623 ucode_install(bam_root);
1619 1624 #endif
1620 1625
1621 1626 ret = f(bam_root, opt);
1622 1627
1623 1628 bam_update_all = 0;
1624 1629
1625 1630 return (ret);
1626 1631 }
1627 1632
1628 1633 /*PRINTFLIKE1*/
1629 1634 void
1630 1635 bam_error(char *format, ...)
1631 1636 {
1632 1637 va_list ap;
1633 1638
1634 1639 va_start(ap, format);
1635 1640 (void) fprintf(stderr, "%s: ", prog);
1636 1641 (void) vfprintf(stderr, format, ap);
1637 1642 va_end(ap);
1638 1643 }
1639 1644
1640 1645 /*PRINTFLIKE1*/
1641 1646 void
1642 1647 bam_derror(char *format, ...)
1643 1648 {
1644 1649 va_list ap;
1645 1650
1646 1651 assert(bam_debug);
1647 1652
1648 1653 va_start(ap, format);
1649 1654 (void) fprintf(stderr, "DEBUG: ");
1650 1655 (void) vfprintf(stderr, format, ap);
1651 1656 va_end(ap);
1652 1657 }
1653 1658
1654 1659 /*PRINTFLIKE1*/
1655 1660 void
1656 1661 bam_print(char *format, ...)
1657 1662 {
1658 1663 va_list ap;
1659 1664
1660 1665 va_start(ap, format);
1661 1666 (void) vfprintf(stdout, format, ap);
1662 1667 va_end(ap);
1663 1668 }
1664 1669
1665 1670 /*PRINTFLIKE1*/
1666 1671 void
1667 1672 bam_print_stderr(char *format, ...)
1668 1673 {
1669 1674 va_list ap;
1670 1675
1671 1676 va_start(ap, format);
1672 1677 (void) vfprintf(stderr, format, ap);
1673 1678 va_end(ap);
1674 1679 }
1675 1680
1676 1681 void
1677 1682 bam_exit(int excode)
1678 1683 {
1679 1684 restore_env();
1680 1685 bam_unlock();
1681 1686 exit(excode);
1682 1687 }
1683 1688
1684 1689 static void
1685 1690 bam_lock(void)
1686 1691 {
1687 1692 struct flock lock;
1688 1693 pid_t pid;
1689 1694
1690 1695 if (bam_skip_lock)
1691 1696 return;
1692 1697
1693 1698 bam_lock_fd = open(BAM_LOCK_FILE, O_CREAT|O_RDWR, LOCK_FILE_PERMS);
1694 1699 if (bam_lock_fd < 0) {
1695 1700 /*
1696 1701 * We may be invoked early in boot for archive verification.
1697 1702 * In this case, root is readonly and /var/run may not exist.
1698 1703 * Proceed without the lock
1699 1704 */
1700 1705 if (errno == EROFS || errno == ENOENT) {
1701 1706 bam_root_readonly = 1;
1702 1707 return;
1703 1708 }
1704 1709
1705 1710 bam_error(_("failed to open file: %s: %s\n"),
1706 1711 BAM_LOCK_FILE, strerror(errno));
1707 1712 bam_exit(1);
1708 1713 }
1709 1714
1710 1715 lock.l_type = F_WRLCK;
1711 1716 lock.l_whence = SEEK_SET;
1712 1717 lock.l_start = 0;
1713 1718 lock.l_len = 0;
1714 1719
1715 1720 if (fcntl(bam_lock_fd, F_SETLK, &lock) == -1) {
1716 1721 if (errno != EACCES && errno != EAGAIN) {
1717 1722 bam_error(_("failed to lock file: %s: %s\n"),
1718 1723 BAM_LOCK_FILE, strerror(errno));
1719 1724 (void) close(bam_lock_fd);
1720 1725 bam_lock_fd = -1;
1721 1726 bam_exit(1);
1722 1727 }
1723 1728 pid = 0;
1724 1729 (void) pread(bam_lock_fd, &pid, sizeof (pid_t), 0);
1725 1730 bam_print(
1726 1731 _("another instance of bootadm (pid %lu) is running\n"),
1727 1732 pid);
1728 1733
1729 1734 lock.l_type = F_WRLCK;
1730 1735 lock.l_whence = SEEK_SET;
1731 1736 lock.l_start = 0;
1732 1737 lock.l_len = 0;
1733 1738 if (fcntl(bam_lock_fd, F_SETLKW, &lock) == -1) {
1734 1739 bam_error(_("failed to lock file: %s: %s\n"),
1735 1740 BAM_LOCK_FILE, strerror(errno));
1736 1741 (void) close(bam_lock_fd);
1737 1742 bam_lock_fd = -1;
1738 1743 bam_exit(1);
1739 1744 }
1740 1745 }
1741 1746
1742 1747 /* We own the lock now */
1743 1748 pid = getpid();
1744 1749 (void) write(bam_lock_fd, &pid, sizeof (pid));
1745 1750 }
1746 1751
1747 1752 static void
1748 1753 bam_unlock(void)
1749 1754 {
1750 1755 struct flock unlock;
1751 1756
1752 1757 if (bam_skip_lock)
1753 1758 return;
1754 1759
1755 1760 /*
1756 1761 * NOP if we don't hold the lock
1757 1762 */
1758 1763 if (bam_lock_fd < 0) {
1759 1764 return;
1760 1765 }
1761 1766
1762 1767 unlock.l_type = F_UNLCK;
1763 1768 unlock.l_whence = SEEK_SET;
1764 1769 unlock.l_start = 0;
1765 1770 unlock.l_len = 0;
1766 1771
1767 1772 if (fcntl(bam_lock_fd, F_SETLK, &unlock) == -1) {
1768 1773 bam_error(_("failed to unlock file: %s: %s\n"),
1769 1774 BAM_LOCK_FILE, strerror(errno));
1770 1775 }
1771 1776
1772 1777 if (close(bam_lock_fd) == -1) {
1773 1778 bam_error(_("failed to close file: %s: %s\n"),
1774 1779 BAM_LOCK_FILE, strerror(errno));
1775 1780 }
1776 1781 bam_lock_fd = -1;
1777 1782 }
1778 1783
1779 1784 static error_t
1780 1785 list_archive(char *root, char *opt)
1781 1786 {
1782 1787 filelist_t flist;
1783 1788 filelist_t *flistp = &flist;
1784 1789 line_t *lp;
1785 1790
1786 1791 assert(root);
1787 1792 assert(opt == NULL);
1788 1793
1789 1794 flistp->head = flistp->tail = NULL;
1790 1795 if (read_list(root, flistp) != BAM_SUCCESS) {
1791 1796 return (BAM_ERROR);
1792 1797 }
1793 1798 assert(flistp->head && flistp->tail);
1794 1799
1795 1800 for (lp = flistp->head; lp; lp = lp->next) {
1796 1801 bam_print(_("%s\n"), lp->line);
1797 1802 }
1798 1803
1799 1804 filelist_free(flistp);
1800 1805
1801 1806 return (BAM_SUCCESS);
1802 1807 }
1803 1808
1804 1809 /*
1805 1810 * This routine writes a list of lines to a file.
1806 1811 * The list is *not* freed
1807 1812 */
1808 1813 static error_t
1809 1814 list2file(char *root, char *tmp, char *final, line_t *start)
1810 1815 {
1811 1816 char tmpfile[PATH_MAX];
1812 1817 char path[PATH_MAX];
1813 1818 FILE *fp;
1814 1819 int ret;
1815 1820 struct stat sb;
1816 1821 mode_t mode;
1817 1822 uid_t root_uid;
1818 1823 gid_t sys_gid;
1819 1824 struct passwd *pw;
1820 1825 struct group *gp;
1821 1826 const char *fcn = "list2file()";
1822 1827
1823 1828 (void) snprintf(path, sizeof (path), "%s%s", root, final);
1824 1829
1825 1830 if (start == NULL) {
1826 1831 /* Empty GRUB menu */
1827 1832 if (stat(path, &sb) != -1) {
1828 1833 bam_print(_("file is empty, deleting file: %s\n"),
1829 1834 path);
1830 1835 if (unlink(path) != 0) {
1831 1836 bam_error(_("failed to unlink file: %s: %s\n"),
1832 1837 path, strerror(errno));
1833 1838 return (BAM_ERROR);
1834 1839 } else {
1835 1840 return (BAM_SUCCESS);
1836 1841 }
1837 1842 }
1838 1843 return (BAM_SUCCESS);
1839 1844 }
1840 1845
1841 1846 /*
1842 1847 * Preserve attributes of existing file if possible,
1843 1848 * otherwise ask the system for uid/gid of root/sys.
1844 1849 * If all fails, fall back on hard-coded defaults.
1845 1850 */
1846 1851 if (stat(path, &sb) != -1) {
1847 1852 mode = sb.st_mode;
1848 1853 root_uid = sb.st_uid;
1849 1854 sys_gid = sb.st_gid;
1850 1855 } else {
1851 1856 mode = DEFAULT_DEV_MODE;
1852 1857 if ((pw = getpwnam(DEFAULT_DEV_USER)) != NULL) {
1853 1858 root_uid = pw->pw_uid;
1854 1859 } else {
1855 1860 bam_error(_("getpwnam: uid for %s failed, "
1856 1861 "defaulting to %d\n"),
1857 1862 DEFAULT_DEV_USER, DEFAULT_DEV_UID);
1858 1863 root_uid = (uid_t)DEFAULT_DEV_UID;
1859 1864 }
1860 1865 if ((gp = getgrnam(DEFAULT_DEV_GROUP)) != NULL) {
1861 1866 sys_gid = gp->gr_gid;
1862 1867 } else {
1863 1868 bam_error(_("getgrnam: gid for %s failed, "
1864 1869 "defaulting to %d\n"),
1865 1870 DEFAULT_DEV_GROUP, DEFAULT_DEV_GID);
1866 1871 sys_gid = (gid_t)DEFAULT_DEV_GID;
1867 1872 }
1868 1873 }
1869 1874
1870 1875 (void) snprintf(tmpfile, sizeof (tmpfile), "%s%s", root, tmp);
1871 1876
1872 1877 /* Truncate tmpfile first */
1873 1878 fp = fopen(tmpfile, "w");
1874 1879 if (fp == NULL) {
1875 1880 bam_error(_("failed to open file: %s: %s\n"), tmpfile,
1876 1881 strerror(errno));
1877 1882 return (BAM_ERROR);
1878 1883 }
1879 1884 ret = fclose(fp);
1880 1885 INJECT_ERROR1("LIST2FILE_TRUNC_FCLOSE", ret = EOF);
1881 1886 if (ret == EOF) {
1882 1887 bam_error(_("failed to close file: %s: %s\n"),
1883 1888 tmpfile, strerror(errno));
1884 1889 return (BAM_ERROR);
1885 1890 }
1886 1891
1887 1892 /* Now open it in append mode */
1888 1893 fp = fopen(tmpfile, "a");
1889 1894 if (fp == NULL) {
1890 1895 bam_error(_("failed to open file: %s: %s\n"), tmpfile,
1891 1896 strerror(errno));
1892 1897 return (BAM_ERROR);
1893 1898 }
1894 1899
1895 1900 for (; start; start = start->next) {
1896 1901 ret = s_fputs(start->line, fp);
1897 1902 INJECT_ERROR1("LIST2FILE_FPUTS", ret = EOF);
1898 1903 if (ret == EOF) {
1899 1904 bam_error(_("write to file failed: %s: %s\n"),
1900 1905 tmpfile, strerror(errno));
1901 1906 (void) fclose(fp);
1902 1907 return (BAM_ERROR);
1903 1908 }
1904 1909 }
1905 1910
1906 1911 ret = fclose(fp);
1907 1912 INJECT_ERROR1("LIST2FILE_APPEND_FCLOSE", ret = EOF);
1908 1913 if (ret == EOF) {
1909 1914 bam_error(_("failed to close file: %s: %s\n"),
1910 1915 tmpfile, strerror(errno));
1911 1916 return (BAM_ERROR);
1912 1917 }
1913 1918
1914 1919 /*
1915 1920 * Set up desired attributes. Ignore failures on filesystems
1916 1921 * not supporting these operations - pcfs reports unsupported
1917 1922 * operations as EINVAL.
1918 1923 */
1919 1924 ret = chmod(tmpfile, mode);
1920 1925 if (ret == -1 &&
1921 1926 errno != EINVAL && errno != ENOTSUP) {
1922 1927 bam_error(_("chmod operation on %s failed - %s\n"),
1923 1928 tmpfile, strerror(errno));
1924 1929 return (BAM_ERROR);
1925 1930 }
1926 1931
1927 1932 ret = chown(tmpfile, root_uid, sys_gid);
1928 1933 if (ret == -1 &&
1929 1934 errno != EINVAL && errno != ENOTSUP) {
1930 1935 bam_error(_("chgrp operation on %s failed - %s\n"),
1931 1936 tmpfile, strerror(errno));
1932 1937 return (BAM_ERROR);
1933 1938 }
1934 1939
1935 1940 /*
1936 1941 * Do an atomic rename
1937 1942 */
1938 1943 ret = rename(tmpfile, path);
1939 1944 INJECT_ERROR1("LIST2FILE_RENAME", ret = -1);
1940 1945 if (ret != 0) {
1941 1946 bam_error(_("rename to file failed: %s: %s\n"), path,
1942 1947 strerror(errno));
1943 1948 return (BAM_ERROR);
1944 1949 }
1945 1950
1946 1951 BAM_DPRINTF(("%s: wrote file successfully: %s\n", fcn, path));
1947 1952 return (BAM_SUCCESS);
1948 1953 }
1949 1954
1950 1955 /*
1951 1956 * Checks if the path specified (without the file name at the end) exists
1952 1957 * and creates it if not. If the path exists and is not a directory, an attempt
1953 1958 * to unlink is made.
1954 1959 */
1955 1960 static int
1956 1961 setup_path(char *path)
1957 1962 {
1958 1963 char *p;
1959 1964 int ret;
1960 1965 struct stat sb;
1961 1966
1962 1967 p = strrchr(path, '/');
1963 1968 if (p != NULL) {
1964 1969 *p = '\0';
1965 1970 if (stat(path, &sb) != 0 || !(S_ISDIR(sb.st_mode))) {
1966 1971 /* best effort attempt, mkdirp will catch the error */
1967 1972 (void) unlink(path);
1968 1973 if (bam_verbose)
1969 1974 bam_print(_("need to create directory "
1970 1975 "path for %s\n"), path);
1971 1976 ret = mkdirp(path, DIR_PERMS);
1972 1977 if (ret == -1) {
1973 1978 bam_error(_("mkdir of %s failed: %s\n"),
1974 1979 path, strerror(errno));
1975 1980 *p = '/';
1976 1981 return (BAM_ERROR);
1977 1982 }
1978 1983 }
1979 1984 *p = '/';
1980 1985 return (BAM_SUCCESS);
1981 1986 }
1982 1987 return (BAM_SUCCESS);
1983 1988 }
1984 1989
1985 1990 typedef union {
1986 1991 gzFile gzfile;
1987 1992 int fdfile;
1988 1993 } outfile;
1989 1994
1990 1995 typedef struct {
1991 1996 char path[PATH_MAX];
1992 1997 outfile out;
1993 1998 } cachefile;
1994 1999
1995 2000 static int
1996 2001 setup_file(char *base, const char *path, cachefile *cf)
1997 2002 {
1998 2003 int ret;
1999 2004 char *strip;
2000 2005
2001 2006 /* init gzfile or fdfile in case we fail before opening */
2002 2007 if (bam_direct == BAM_DIRECT_DBOOT)
2003 2008 cf->out.gzfile = NULL;
2004 2009 else
2005 2010 cf->out.fdfile = -1;
2006 2011
2007 2012 /* strip the trailing altroot path */
2008 2013 strip = (char *)path + strlen(rootbuf);
2009 2014
2010 2015 ret = snprintf(cf->path, sizeof (cf->path), "%s/%s", base, strip);
2011 2016 if (ret >= sizeof (cf->path)) {
2012 2017 bam_error(_("unable to create path on mountpoint %s, "
2013 2018 "path too long\n"), rootbuf);
2014 2019 return (BAM_ERROR);
2015 2020 }
2016 2021
2017 2022 /* Check if path is present in the archive cache directory */
2018 2023 if (setup_path(cf->path) == BAM_ERROR)
2019 2024 return (BAM_ERROR);
2020 2025
2021 2026 if (bam_direct == BAM_DIRECT_DBOOT) {
2022 2027 if ((cf->out.gzfile = gzopen(cf->path, "wb")) == NULL) {
2023 2028 bam_error(_("failed to open file: %s: %s\n"),
2024 2029 cf->path, strerror(errno));
2025 2030 return (BAM_ERROR);
2026 2031 }
2027 2032 (void) gzsetparams(cf->out.gzfile, Z_BEST_SPEED,
2028 2033 Z_DEFAULT_STRATEGY);
2029 2034 } else {
2030 2035 if ((cf->out.fdfile = open(cf->path, O_WRONLY | O_CREAT, 0644))
2031 2036 == -1) {
2032 2037 bam_error(_("failed to open file: %s: %s\n"),
2033 2038 cf->path, strerror(errno));
2034 2039 return (BAM_ERROR);
2035 2040 }
2036 2041 }
2037 2042
2038 2043 return (BAM_SUCCESS);
2039 2044 }
2040 2045
2041 2046 static int
2042 2047 cache_write(cachefile cf, char *buf, int size)
2043 2048 {
2044 2049 int err;
2045 2050
2046 2051 if (bam_direct == BAM_DIRECT_DBOOT) {
2047 2052 if (gzwrite(cf.out.gzfile, buf, size) < 1) {
2048 2053 bam_error(_("failed to write to %s\n"),
2049 2054 gzerror(cf.out.gzfile, &err));
2050 2055 if (err == Z_ERRNO && bam_verbose) {
2051 2056 bam_error(_("write to file failed: %s: %s\n"),
2052 2057 cf.path, strerror(errno));
2053 2058 }
2054 2059 return (BAM_ERROR);
2055 2060 }
2056 2061 } else {
2057 2062 if (write(cf.out.fdfile, buf, size) < 1) {
2058 2063 bam_error(_("write to file failed: %s: %s\n"),
2059 2064 cf.path, strerror(errno));
2060 2065 return (BAM_ERROR);
2061 2066 }
2062 2067 }
2063 2068 return (BAM_SUCCESS);
2064 2069 }
2065 2070
2066 2071 static int
2067 2072 cache_close(cachefile cf)
2068 2073 {
2069 2074 int ret;
2070 2075
2071 2076 if (bam_direct == BAM_DIRECT_DBOOT) {
2072 2077 if (cf.out.gzfile) {
2073 2078 ret = gzclose(cf.out.gzfile);
2074 2079 if (ret != Z_OK) {
2075 2080 bam_error(_("failed to close file: %s: %s\n"),
2076 2081 cf.path, strerror(errno));
2077 2082 return (BAM_ERROR);
2078 2083 }
2079 2084 }
2080 2085 } else {
2081 2086 if (cf.out.fdfile != -1) {
2082 2087 ret = close(cf.out.fdfile);
2083 2088 if (ret != 0) {
2084 2089 bam_error(_("failed to close file: %s: %s\n"),
2085 2090 cf.path, strerror(errno));
2086 2091 return (BAM_ERROR);
2087 2092 }
2088 2093 }
2089 2094 }
2090 2095
2091 2096 return (BAM_SUCCESS);
2092 2097 }
2093 2098
2094 2099 static int
2095 2100 dircache_updatefile(const char *path)
2096 2101 {
2097 2102 int ret, exitcode;
2098 2103 char buf[4096 * 4];
2099 2104 FILE *infile;
2100 2105 cachefile outfile, outupdt;
2101 2106
2102 2107 if (bam_nowrite()) {
2103 2108 set_dir_flag(NEED_UPDATE);
2104 2109 return (BAM_SUCCESS);
2105 2110 }
2106 2111
2107 2112 if (!has_cachedir())
2108 2113 return (BAM_SUCCESS);
2109 2114
2110 2115 if ((infile = fopen(path, "rb")) == NULL) {
2111 2116 bam_error(_("failed to open file: %s: %s\n"), path,
2112 2117 strerror(errno));
2113 2118 return (BAM_ERROR);
2114 2119 }
2115 2120
2116 2121 ret = setup_file(get_cachedir(), path, &outfile);
2117 2122 if (ret == BAM_ERROR) {
2118 2123 exitcode = BAM_ERROR;
2119 2124 goto out;
2120 2125 }
2121 2126 if (!is_dir_flag_on(NO_EXTEND)) {
2122 2127 ret = setup_file(get_updatedir(), path, &outupdt);
2123 2128 if (ret == BAM_ERROR)
2124 2129 set_dir_flag(NO_EXTEND);
2125 2130 }
2126 2131
2127 2132 while ((ret = fread(buf, 1, sizeof (buf), infile)) > 0) {
2128 2133 if (cache_write(outfile, buf, ret) == BAM_ERROR) {
2129 2134 exitcode = BAM_ERROR;
2130 2135 goto out;
2131 2136 }
2132 2137 if (!is_dir_flag_on(NO_EXTEND))
2133 2138 if (cache_write(outupdt, buf, ret) == BAM_ERROR)
2134 2139 set_dir_flag(NO_EXTEND);
2135 2140 }
2136 2141
2137 2142 set_dir_flag(NEED_UPDATE);
2138 2143 get_count()++;
2139 2144 if (get_count() > COUNT_MAX)
2140 2145 set_dir_flag(NO_EXTEND);
2141 2146 exitcode = BAM_SUCCESS;
2142 2147 out:
2143 2148 (void) fclose(infile);
2144 2149 if (cache_close(outfile) == BAM_ERROR)
2145 2150 exitcode = BAM_ERROR;
2146 2151 if (!is_dir_flag_on(NO_EXTEND) &&
2147 2152 cache_close(outupdt) == BAM_ERROR)
2148 2153 exitcode = BAM_ERROR;
2149 2154 if (exitcode == BAM_ERROR)
2150 2155 set_flag(UPDATE_ERROR);
2151 2156 return (exitcode);
2152 2157 }
2153 2158
2154 2159 static int
2155 2160 dircache_updatedir(const char *path, int updt)
2156 2161 {
2157 2162 int ret;
2158 2163 char dpath[PATH_MAX];
2159 2164 char *strip;
2160 2165 struct stat sb;
2161 2166
2162 2167 strip = (char *)path + strlen(rootbuf);
2163 2168
2164 2169 ret = snprintf(dpath, sizeof (dpath), "%s/%s", updt ?
2165 2170 get_updatedir() : get_cachedir(), strip);
2166 2171
2167 2172 if (ret >= sizeof (dpath)) {
2168 2173 bam_error(_("unable to create path on mountpoint %s, "
2169 2174 "path too long\n"), rootbuf);
2170 2175 set_flag(UPDATE_ERROR);
2171 2176 return (BAM_ERROR);
2172 2177 }
2173 2178
2174 2179 if (stat(dpath, &sb) == 0 && S_ISDIR(sb.st_mode))
2175 2180 return (BAM_SUCCESS);
2176 2181
2177 2182 if (updt) {
2178 2183 if (!is_dir_flag_on(NO_EXTEND))
2179 2184 if (!bam_nowrite() && mkdirp(dpath, DIR_PERMS) == -1)
2180 2185 set_dir_flag(NO_EXTEND);
2181 2186 } else {
2182 2187 if (!bam_nowrite() && mkdirp(dpath, DIR_PERMS) == -1) {
2183 2188 set_flag(UPDATE_ERROR);
2184 2189 return (BAM_ERROR);
2185 2190 }
2186 2191 }
2187 2192
2188 2193 set_dir_flag(NEED_UPDATE);
2189 2194 return (BAM_SUCCESS);
2190 2195 }
2191 2196
2192 2197 #define DO_CACHE_DIR 0
2193 2198 #define DO_UPDATE_DIR 1
2194 2199
2195 2200 #if defined(_LP64) || defined(_LONGLONG_TYPE)
2196 2201 typedef Elf64_Ehdr _elfhdr;
2197 2202 #else
2198 2203 typedef Elf32_Ehdr _elfhdr;
2199 2204 #endif
2200 2205
2201 2206 /*
2202 2207 * This routine updates the contents of the cache directory
2203 2208 */
2204 2209 static int
2205 2210 update_dircache(const char *path, int flags)
2206 2211 {
2207 2212 int rc = BAM_SUCCESS;
2208 2213
2209 2214 switch (flags) {
2210 2215 case FTW_F:
2211 2216 {
2212 2217 int fd;
2213 2218 _elfhdr elf;
2214 2219
2215 2220 if ((fd = open(path, O_RDONLY)) < 0) {
2216 2221 bam_error(_("failed to open file: %s: %s\n"),
2217 2222 path, strerror(errno));
2218 2223 set_flag(UPDATE_ERROR);
2219 2224 rc = BAM_ERROR;
2220 2225 break;
2221 2226 }
2222 2227
2223 2228 /*
2224 2229 * libelf and gelf would be a cleaner and easier way to handle
2225 2230 * this, but libelf fails compilation if _ILP32 is defined &&
2226 2231 * _FILE_OFFSET_BITS is != 32 ...
2227 2232 */
2228 2233 if (read(fd, (void *)&elf, sizeof (_elfhdr)) < 0) {
2229 2234 bam_error(_("read failed for file: %s: %s\n"),
2230 2235 path, strerror(errno));
2231 2236 set_flag(UPDATE_ERROR);
2232 2237 (void) close(fd);
2233 2238 rc = BAM_ERROR;
2234 2239 break;
2235 2240 }
2236 2241 (void) close(fd);
2237 2242
2238 2243 if (memcmp(elf.e_ident, ELFMAG, 4) != 0) {
2239 2244 /* Not an ELF file, include in archive */
2240 2245 rc = dircache_updatefile(path);
2241 2246 } else {
2242 2247 /* Include 64-bit ELF files only */
2243 2248 switch (elf.e_ident[EI_CLASS]) {
2244 2249 case ELFCLASS32:
2245 2250 bam_print(_("WARNING: ELF file %s is 32-bit "
2246 2251 "and will be excluded\n"), path);
2247 2252 break;
2248 2253 case ELFCLASS64:
2249 2254 rc = dircache_updatefile(path);
2250 2255 break;
2251 2256 default:
2252 2257 bam_print(_("WARNING: ELF file %s is neither "
2253 2258 "32-bit nor 64-bit\n"), path);
2254 2259 break;
2255 2260 }
2256 2261 }
2257 2262 break;
2258 2263 }
2259 2264 case FTW_D:
2260 2265 if (strstr(path, "/amd64") != NULL) {
2261 2266 if (has_cachedir()) {
2262 2267 rc = dircache_updatedir(path, DO_UPDATE_DIR);
2263 2268 if (rc == BAM_SUCCESS)
2264 2269 rc = dircache_updatedir(path,
2265 2270 DO_CACHE_DIR);
2266 2271 }
2267 2272 }
2268 2273 break;
2269 2274 default:
2270 2275 rc = BAM_ERROR;
2271 2276 break;
2272 2277 }
2273 2278
2274 2279 return (rc);
2275 2280 }
2276 2281
2277 2282 /*ARGSUSED*/
2278 2283 static int
2279 2284 cmpstat(
2280 2285 const char *file,
2281 2286 const struct stat *st,
2282 2287 int flags,
2283 2288 struct FTW *ftw)
2284 2289 {
2285 2290 uint_t sz;
2286 2291 uint64_t *value;
2287 2292 uint64_t filestat[2];
2288 2293 int error, ret, status;
2289 2294
2290 2295 struct safefile *safefilep;
2291 2296 FILE *fp;
2292 2297 struct stat sb;
2293 2298 regex_t re;
2294 2299
2295 2300 /*
2296 2301 * On SPARC we create/update links too.
2297 2302 */
2298 2303 if (flags != FTW_F && flags != FTW_D && (flags == FTW_SL &&
2299 2304 !is_flag_on(IS_SPARC_TARGET)))
2300 2305 return (0);
2301 2306
2302 2307 /*
2303 2308 * Ignore broken links
2304 2309 */
2305 2310 if (flags == FTW_SL && stat(file, &sb) < 0)
2306 2311 return (0);
2307 2312
2308 2313 /*
2309 2314 * new_nvlp may be NULL if there were errors earlier
2310 2315 * but this is not fatal to update determination.
2311 2316 */
2312 2317 if (walk_arg.new_nvlp) {
2313 2318 filestat[0] = st->st_size;
2314 2319 filestat[1] = st->st_mtime;
2315 2320 error = nvlist_add_uint64_array(walk_arg.new_nvlp,
2316 2321 file + bam_rootlen, filestat, 2);
2317 2322 if (error)
2318 2323 bam_error(_("failed to update stat data for: %s: %s\n"),
2319 2324 file, strerror(error));
2320 2325 }
2321 2326
2322 2327 /*
2323 2328 * If we are invoked as part of system/filesystem/boot-archive, then
2324 2329 * there are a number of things we should not worry about
2325 2330 */
2326 2331 if (bam_smf_check) {
2327 2332 /* ignore amd64 modules unless we are booted amd64. */
2328 2333 if (!is_amd64() && strstr(file, "/amd64/") != 0)
2329 2334 return (0);
2330 2335
2331 2336 /* read in list of safe files */
2332 2337 if (safefiles == NULL) {
2333 2338 fp = fopen("/boot/solaris/filelist.safe", "r");
2334 2339 if (fp != NULL) {
2335 2340 safefiles = s_calloc(1,
2336 2341 sizeof (struct safefile));
2337 2342 safefilep = safefiles;
2338 2343 safefilep->name = s_calloc(1, MAXPATHLEN +
2339 2344 MAXNAMELEN);
2340 2345 safefilep->next = NULL;
2341 2346 while (s_fgets(safefilep->name, MAXPATHLEN +
2342 2347 MAXNAMELEN, fp) != NULL) {
2343 2348 safefilep->next = s_calloc(1,
2344 2349 sizeof (struct safefile));
2345 2350 safefilep = safefilep->next;
2346 2351 safefilep->name = s_calloc(1,
2347 2352 MAXPATHLEN + MAXNAMELEN);
2348 2353 safefilep->next = NULL;
2349 2354 }
2350 2355 (void) fclose(fp);
2351 2356 }
2352 2357 }
2353 2358 }
2354 2359
2355 2360 /*
2356 2361 * On SPARC we create a -path-list file for mkisofs
2357 2362 */
2358 2363 if (is_flag_on(IS_SPARC_TARGET) && !bam_nowrite()) {
2359 2364 if (flags != FTW_D) {
2360 2365 char *strip;
2361 2366
2362 2367 strip = (char *)file + strlen(rootbuf);
2363 2368 (void) fprintf(walk_arg.sparcfile, "/%s=%s\n", strip,
2364 2369 file);
2365 2370 }
2366 2371 }
2367 2372
2368 2373 /*
2369 2374 * We are transitioning from the old model to the dircache or the cache
2370 2375 * directory was removed: create the entry without further checkings.
2371 2376 */
2372 2377 if (is_flag_on(NEED_CACHE_DIR)) {
2373 2378 if (bam_verbose)
2374 2379 bam_print(_(" new %s\n"), file);
2375 2380
2376 2381 if (is_flag_on(IS_SPARC_TARGET)) {
2377 2382 set_dir_flag(NEED_UPDATE);
2378 2383 return (0);
2379 2384 }
2380 2385
2381 2386 ret = update_dircache(file, flags);
2382 2387 if (ret == BAM_ERROR) {
2383 2388 bam_error(_("directory cache update failed for %s\n"),
2384 2389 file);
2385 2390 return (-1);
2386 2391 }
2387 2392
2388 2393 return (0);
2389 2394 }
2390 2395
2391 2396 /*
2392 2397 * We need an update if file doesn't exist in old archive
2393 2398 */
2394 2399 if (walk_arg.old_nvlp == NULL ||
2395 2400 nvlist_lookup_uint64_array(walk_arg.old_nvlp,
2396 2401 file + bam_rootlen, &value, &sz) != 0) {
2397 2402 if (bam_smf_check) /* ignore new during smf check */
2398 2403 return (0);
2399 2404
2400 2405 if (is_flag_on(IS_SPARC_TARGET)) {
2401 2406 set_dir_flag(NEED_UPDATE);
2402 2407 } else {
2403 2408 ret = update_dircache(file, flags);
2404 2409 if (ret == BAM_ERROR) {
2405 2410 bam_error(_("directory cache update "
2406 2411 "failed for %s\n"), file);
2407 2412 return (-1);
2408 2413 }
2409 2414 }
2410 2415
2411 2416 if (bam_verbose)
2412 2417 bam_print(_(" new %s\n"), file);
2413 2418 return (0);
2414 2419 }
2415 2420
2416 2421 /*
2417 2422 * If we got there, the file is already listed as to be included in the
2418 2423 * iso image. We just need to know if we are going to rebuild it or not
2419 2424 */
2420 2425 if (is_flag_on(IS_SPARC_TARGET) &&
2421 2426 is_dir_flag_on(NEED_UPDATE) && !bam_nowrite())
2422 2427 return (0);
2423 2428 /*
2424 2429 * File exists in old archive. Check if file has changed
2425 2430 */
2426 2431 assert(sz == 2);
2427 2432 bcopy(value, filestat, sizeof (filestat));
2428 2433
2429 2434 if (flags != FTW_D && (filestat[0] != st->st_size ||
2430 2435 filestat[1] != st->st_mtime)) {
2431 2436 if (bam_smf_check) {
2432 2437 safefilep = safefiles;
2433 2438 while (safefilep != NULL &&
2434 2439 safefilep->name[0] != '\0') {
2435 2440 if (regcomp(&re, safefilep->name,
2436 2441 REG_EXTENDED|REG_NOSUB) == 0) {
2437 2442 status = regexec(&re,
2438 2443 file + bam_rootlen, 0, NULL, 0);
2439 2444 regfree(&re);
2440 2445 if (status == 0) {
2441 2446 (void) creat(
2442 2447 NEED_UPDATE_SAFE_FILE,
2443 2448 0644);
2444 2449 return (0);
2445 2450 }
2446 2451 }
2447 2452 safefilep = safefilep->next;
2448 2453 }
2449 2454 }
2450 2455
2451 2456 if (is_flag_on(IS_SPARC_TARGET)) {
↓ open down ↓ |
2156 lines elided |
↑ open up ↑ |
2452 2457 set_dir_flag(NEED_UPDATE);
2453 2458 } else {
2454 2459 ret = update_dircache(file, flags);
2455 2460 if (ret == BAM_ERROR) {
2456 2461 bam_error(_("directory cache update failed "
2457 2462 "for %s\n"), file);
2458 2463 return (-1);
2459 2464 }
2460 2465 }
2461 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 +
2462 2480 if (bam_verbose) {
2463 2481 if (bam_smf_check)
2464 2482 bam_print(" %s\n", file);
2465 2483 else
2466 2484 bam_print(_(" changed %s\n"), file);
2467 2485 }
2468 2486 }
2469 2487
2470 2488 return (0);
2471 2489 }
2472 2490
2473 2491 /*
2474 2492 * Remove a directory path recursively
2475 2493 */
2476 2494 static int
2477 2495 rmdir_r(char *path)
2478 2496 {
2479 2497 struct dirent *d = NULL;
2480 2498 DIR *dir = NULL;
2481 2499 char tpath[PATH_MAX];
2482 2500 struct stat sb;
2483 2501
2484 2502 if ((dir = opendir(path)) == NULL)
2485 2503 return (-1);
2486 2504
2487 2505 while ((d = readdir(dir)) != NULL) {
2488 2506 if ((strcmp(d->d_name, ".") != 0) &&
2489 2507 (strcmp(d->d_name, "..") != 0)) {
2490 2508 (void) snprintf(tpath, sizeof (tpath), "%s/%s",
2491 2509 path, d->d_name);
2492 2510 if (stat(tpath, &sb) == 0) {
2493 2511 if (sb.st_mode & S_IFDIR)
2494 2512 (void) rmdir_r(tpath);
2495 2513 else
2496 2514 (void) remove(tpath);
2497 2515 }
2498 2516 }
2499 2517 }
2500 2518 return (remove(path));
2501 2519 }
2502 2520
2503 2521 /*
2504 2522 * Check if cache directory exists and, if not, create it and update flags
2505 2523 * accordingly. If the path exists, but it's not a directory, a best effort
2506 2524 * attempt to remove and recreate it is made.
2507 2525 * If the user requested a 'purge', always recreate the directory from scratch.
2508 2526 */
2509 2527 static int
2510 2528 set_cache_dir(char *root)
2511 2529 {
2512 2530 struct stat sb;
2513 2531 int ret = 0;
2514 2532
2515 2533 ret = build_path(get_cachedir(), sizeof (get_cachedir()),
2516 2534 root, ARCHIVE_PREFIX, CACHEDIR_SUFFIX);
2517 2535
2518 2536 if (ret >= sizeof (get_cachedir())) {
2519 2537 bam_error(_("unable to create path on mountpoint %s, "
2520 2538 "path too long\n"), rootbuf);
2521 2539 return (BAM_ERROR);
2522 2540 }
2523 2541
2524 2542 if (bam_purge || is_flag_on(INVALIDATE_CACHE))
2525 2543 (void) rmdir_r(get_cachedir());
2526 2544
2527 2545 if (stat(get_cachedir(), &sb) != 0 || !(S_ISDIR(sb.st_mode))) {
2528 2546 /* best effort unlink attempt, mkdir will catch errors */
2529 2547 (void) unlink(get_cachedir());
2530 2548
2531 2549 if (bam_verbose)
2532 2550 bam_print(_("archive cache directory not found: %s\n"),
2533 2551 get_cachedir());
2534 2552 ret = mkdir(get_cachedir(), DIR_PERMS);
2535 2553 if (ret < 0) {
2536 2554 bam_error(_("mkdir of %s failed: %s\n"),
2537 2555 get_cachedir(), strerror(errno));
2538 2556 get_cachedir()[0] = '\0';
2539 2557 return (ret);
2540 2558 }
2541 2559 set_flag(NEED_CACHE_DIR);
2542 2560 set_dir_flag(NO_EXTEND);
2543 2561 }
2544 2562
2545 2563 return (BAM_SUCCESS);
2546 2564 }
2547 2565
2548 2566 static int
2549 2567 set_update_dir(char *root)
2550 2568 {
2551 2569 struct stat sb;
2552 2570 int ret;
2553 2571
2554 2572 if (is_dir_flag_on(NO_EXTEND))
2555 2573 return (BAM_SUCCESS);
2556 2574
2557 2575 if (!bam_extend) {
2558 2576 set_dir_flag(NO_EXTEND);
2559 2577 return (BAM_SUCCESS);
2560 2578 }
2561 2579
2562 2580 ret = build_path(get_updatedir(), sizeof (get_updatedir()),
2563 2581 root, ARCHIVE_PREFIX, UPDATEDIR_SUFFIX);
2564 2582
2565 2583 if (ret >= sizeof (get_updatedir())) {
2566 2584 bam_error(_("unable to create path on mountpoint %s, "
2567 2585 "path too long\n"), rootbuf);
2568 2586 return (BAM_ERROR);
2569 2587 }
2570 2588
2571 2589 if (stat(get_updatedir(), &sb) == 0) {
2572 2590 if (S_ISDIR(sb.st_mode))
2573 2591 ret = rmdir_r(get_updatedir());
2574 2592 else
2575 2593 ret = unlink(get_updatedir());
2576 2594
2577 2595 if (ret != 0)
2578 2596 set_dir_flag(NO_EXTEND);
2579 2597 }
2580 2598
2581 2599 if (mkdir(get_updatedir(), DIR_PERMS) < 0)
2582 2600 set_dir_flag(NO_EXTEND);
2583 2601
2584 2602 return (BAM_SUCCESS);
2585 2603 }
2586 2604
2587 2605 static int
2588 2606 is_valid_archive(char *root)
2589 2607 {
2590 2608 char archive_path[PATH_MAX];
2591 2609 char timestamp_path[PATH_MAX];
2592 2610 struct stat sb, timestamp;
2593 2611 int ret;
2594 2612
2595 2613 ret = build_path(archive_path, sizeof (archive_path),
2596 2614 root, ARCHIVE_PREFIX, ARCHIVE_SUFFIX);
2597 2615
2598 2616 if (ret >= sizeof (archive_path)) {
2599 2617 bam_error(_("unable to create path on mountpoint %s, "
2600 2618 "path too long\n"), rootbuf);
2601 2619 return (BAM_ERROR);
2602 2620 }
2603 2621
2604 2622 if (stat(archive_path, &sb) != 0) {
2605 2623 if (bam_verbose && !bam_check)
2606 2624 bam_print(_("archive not found: %s\n"), archive_path);
2607 2625 set_dir_flag(NEED_UPDATE | NO_EXTEND);
2608 2626 return (BAM_SUCCESS);
2609 2627 }
2610 2628
2611 2629 /*
2612 2630 * The timestamp file is used to prevent stale files in the archive
2613 2631 * cache.
2614 2632 * Stale files can happen if the system is booted back and forth across
2615 2633 * the transition from bootadm-before-the-cache to
2616 2634 * bootadm-after-the-cache, since older versions of bootadm don't know
2617 2635 * about the existence of the archive cache.
2618 2636 *
2619 2637 * Since only bootadm-after-the-cache versions know about about this
2620 2638 * file, we require that the boot archive be older than this file.
2621 2639 */
2622 2640 ret = snprintf(timestamp_path, sizeof (timestamp_path), "%s%s", root,
2623 2641 FILE_STAT_TIMESTAMP);
2624 2642
2625 2643 if (ret >= sizeof (timestamp_path)) {
2626 2644 bam_error(_("unable to create path on mountpoint %s, "
2627 2645 "path too long\n"), rootbuf);
2628 2646 return (BAM_ERROR);
2629 2647 }
2630 2648
2631 2649 if (stat(timestamp_path, ×tamp) != 0 ||
2632 2650 sb.st_mtime > timestamp.st_mtime) {
2633 2651 if (bam_verbose && !bam_check)
2634 2652 bam_print(
2635 2653 _("archive cache is out of sync. Rebuilding.\n"));
2636 2654 /*
2637 2655 * Don't generate a false positive for the boot-archive service
2638 2656 * but trigger an update of the archive cache in
2639 2657 * boot-archive-update.
2640 2658 */
2641 2659 if (bam_smf_check) {
2642 2660 (void) creat(NEED_UPDATE_FILE, 0644);
2643 2661 return (BAM_SUCCESS);
2644 2662 }
2645 2663
2646 2664 set_flag(INVALIDATE_CACHE);
2647 2665 set_dir_flag(NEED_UPDATE | NO_EXTEND);
2648 2666 return (BAM_SUCCESS);
2649 2667 }
2650 2668
2651 2669 if (is_flag_on(IS_SPARC_TARGET))
2652 2670 return (BAM_SUCCESS);
2653 2671
2654 2672 if (bam_extend && sb.st_size > BA_SIZE_MAX) {
2655 2673 if (bam_verbose && !bam_check)
2656 2674 bam_print(_("archive %s is bigger than %d bytes and "
2657 2675 "will be rebuilt\n"), archive_path, BA_SIZE_MAX);
2658 2676 set_dir_flag(NO_EXTEND);
2659 2677 }
2660 2678
2661 2679 return (BAM_SUCCESS);
2662 2680 }
2663 2681
2664 2682 /*
2665 2683 * Check flags and presence of required files and directories.
2666 2684 * The force flag and/or absence of files should
2667 2685 * trigger an update.
2668 2686 * Suppress stdout output if check (-n) option is set
2669 2687 * (as -n should only produce parseable output.)
2670 2688 */
2671 2689 static int
2672 2690 check_flags_and_files(char *root)
2673 2691 {
2674 2692
2675 2693 struct stat sb;
2676 2694 int ret;
2677 2695
2678 2696 /*
2679 2697 * If archive is missing, create archive
2680 2698 */
2681 2699 ret = is_valid_archive(root);
2682 2700 if (ret == BAM_ERROR)
2683 2701 return (BAM_ERROR);
2684 2702
2685 2703 if (bam_nowrite())
2686 2704 return (BAM_SUCCESS);
2687 2705
2688 2706 /*
2689 2707 * check if cache directories exist on x86.
2690 2708 * check (and always open) the cache file on SPARC.
2691 2709 */
2692 2710 if (is_sparc()) {
2693 2711 ret = snprintf(get_cachedir(),
2694 2712 sizeof (get_cachedir()), "%s%s%s/%s", root,
2695 2713 ARCHIVE_PREFIX, get_machine(), CACHEDIR_SUFFIX);
2696 2714
2697 2715 if (ret >= sizeof (get_cachedir())) {
2698 2716 bam_error(_("unable to create path on mountpoint %s, "
2699 2717 "path too long\n"), rootbuf);
2700 2718 return (BAM_ERROR);
2701 2719 }
2702 2720
2703 2721 if (stat(get_cachedir(), &sb) != 0) {
2704 2722 set_flag(NEED_CACHE_DIR);
2705 2723 set_dir_flag(NEED_UPDATE);
2706 2724 }
2707 2725
2708 2726 walk_arg.sparcfile = fopen(get_cachedir(), "w");
2709 2727 if (walk_arg.sparcfile == NULL) {
2710 2728 bam_error(_("failed to open file: %s: %s\n"),
2711 2729 get_cachedir(), strerror(errno));
2712 2730 return (BAM_ERROR);
2713 2731 }
2714 2732
2715 2733 set_dir_present();
2716 2734 } else {
2717 2735 if (set_cache_dir(root) != 0)
2718 2736 return (BAM_ERROR);
2719 2737
2720 2738 set_dir_present();
2721 2739
2722 2740 if (set_update_dir(root) != 0)
2723 2741 return (BAM_ERROR);
2724 2742 }
2725 2743
2726 2744 /*
2727 2745 * if force, create archive unconditionally
2728 2746 */
2729 2747 if (bam_force) {
2730 2748 set_dir_flag(NEED_UPDATE);
2731 2749 if (bam_verbose)
2732 2750 bam_print(_("forced update of archive requested\n"));
2733 2751 return (BAM_SUCCESS);
2734 2752 }
2735 2753
2736 2754 return (BAM_SUCCESS);
2737 2755 }
2738 2756
2739 2757 static error_t
2740 2758 read_one_list(char *root, filelist_t *flistp, char *filelist)
2741 2759 {
2742 2760 char path[PATH_MAX];
2743 2761 FILE *fp;
2744 2762 char buf[BAM_MAXLINE];
2745 2763 const char *fcn = "read_one_list()";
2746 2764
2747 2765 (void) snprintf(path, sizeof (path), "%s%s", root, filelist);
2748 2766
2749 2767 fp = fopen(path, "r");
2750 2768 if (fp == NULL) {
2751 2769 BAM_DPRINTF(("%s: failed to open archive filelist: %s: %s\n",
2752 2770 fcn, path, strerror(errno)));
2753 2771 return (BAM_ERROR);
2754 2772 }
2755 2773 while (s_fgets(buf, sizeof (buf), fp) != NULL) {
2756 2774 /* skip blank lines */
2757 2775 if (strspn(buf, " \t") == strlen(buf))
2758 2776 continue;
2759 2777 append_to_flist(flistp, buf);
2760 2778 }
2761 2779 if (fclose(fp) != 0) {
2762 2780 bam_error(_("failed to close file: %s: %s\n"),
2763 2781 path, strerror(errno));
2764 2782 return (BAM_ERROR);
2765 2783 }
2766 2784 return (BAM_SUCCESS);
2767 2785 }
2768 2786
2769 2787 static error_t
2770 2788 read_list(char *root, filelist_t *flistp)
2771 2789 {
2772 2790 char path[PATH_MAX];
2773 2791 char cmd[PATH_MAX];
2774 2792 struct stat sb;
2775 2793 int n, rval;
2776 2794 const char *fcn = "read_list()";
2777 2795
2778 2796 flistp->head = flistp->tail = NULL;
2779 2797
2780 2798 /*
2781 2799 * build and check path to extract_boot_filelist.ksh
2782 2800 */
2783 2801 n = snprintf(path, sizeof (path), "%s%s", root, EXTRACT_BOOT_FILELIST);
2784 2802 if (n >= sizeof (path)) {
2785 2803 bam_error(_("archive filelist is empty\n"));
2786 2804 return (BAM_ERROR);
2787 2805 }
2788 2806
2789 2807 if (is_safe_exec(path) == BAM_ERROR)
2790 2808 return (BAM_ERROR);
2791 2809
2792 2810 /*
2793 2811 * If extract_boot_filelist is present, exec it, otherwise read
2794 2812 * the filelists directly, for compatibility with older images.
2795 2813 */
2796 2814 if (stat(path, &sb) == 0) {
2797 2815 /*
2798 2816 * build arguments to exec extract_boot_filelist.ksh
2799 2817 */
2800 2818 char *rootarg, *platarg;
2801 2819 int platarglen = 1, rootarglen = 1;
2802 2820 if (strlen(root) > 1)
2803 2821 rootarglen += strlen(root) + strlen("-R ");
2804 2822 if (bam_alt_platform)
2805 2823 platarglen += strlen(bam_platform) + strlen("-p ");
2806 2824 platarg = s_calloc(1, platarglen);
2807 2825 rootarg = s_calloc(1, rootarglen);
2808 2826 *platarg = 0;
2809 2827 *rootarg = 0;
2810 2828
2811 2829 if (strlen(root) > 1) {
2812 2830 (void) snprintf(rootarg, rootarglen,
2813 2831 "-R %s", root);
2814 2832 }
2815 2833 if (bam_alt_platform) {
2816 2834 (void) snprintf(platarg, platarglen,
2817 2835 "-p %s", bam_platform);
2818 2836 }
2819 2837 n = snprintf(cmd, sizeof (cmd), "%s %s %s /%s /%s",
2820 2838 path, rootarg, platarg, BOOT_FILE_LIST, ETC_FILE_LIST);
2821 2839 free(platarg);
2822 2840 free(rootarg);
2823 2841 if (n >= sizeof (cmd)) {
2824 2842 bam_error(_("archive filelist is empty\n"));
2825 2843 return (BAM_ERROR);
2826 2844 }
2827 2845 if (exec_cmd(cmd, flistp) != 0) {
2828 2846 BAM_DPRINTF(("%s: failed to open archive "
2829 2847 "filelist: %s: %s\n", fcn, path, strerror(errno)));
2830 2848 return (BAM_ERROR);
2831 2849 }
2832 2850 } else {
2833 2851 /*
2834 2852 * Read current lists of files - only the first is mandatory
2835 2853 */
2836 2854 rval = read_one_list(root, flistp, BOOT_FILE_LIST);
2837 2855 if (rval != BAM_SUCCESS)
2838 2856 return (rval);
2839 2857 (void) read_one_list(root, flistp, ETC_FILE_LIST);
2840 2858 }
2841 2859
2842 2860 if (flistp->head == NULL) {
2843 2861 bam_error(_("archive filelist is empty\n"));
2844 2862 return (BAM_ERROR);
2845 2863 }
2846 2864
2847 2865 return (BAM_SUCCESS);
2848 2866 }
2849 2867
2850 2868 static void
2851 2869 getoldstat(char *root)
2852 2870 {
2853 2871 char path[PATH_MAX];
2854 2872 int fd, error;
2855 2873 struct stat sb;
2856 2874 char *ostat;
2857 2875
2858 2876 (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT);
2859 2877 fd = open(path, O_RDONLY);
2860 2878 if (fd == -1) {
2861 2879 if (bam_verbose)
2862 2880 bam_print(_("failed to open file: %s: %s\n"),
2863 2881 path, strerror(errno));
2864 2882 goto out_err;
2865 2883 }
2866 2884
2867 2885 if (fstat(fd, &sb) != 0) {
2868 2886 bam_error(_("stat of file failed: %s: %s\n"), path,
2869 2887 strerror(errno));
2870 2888 goto out_err;
2871 2889 }
2872 2890
2873 2891 ostat = s_calloc(1, sb.st_size);
2874 2892
2875 2893 if (read(fd, ostat, sb.st_size) != sb.st_size) {
2876 2894 bam_error(_("read failed for file: %s: %s\n"), path,
2877 2895 strerror(errno));
2878 2896 free(ostat);
2879 2897 goto out_err;
2880 2898 }
2881 2899
2882 2900 (void) close(fd);
2883 2901 fd = -1;
2884 2902
2885 2903 walk_arg.old_nvlp = NULL;
2886 2904 error = nvlist_unpack(ostat, sb.st_size, &walk_arg.old_nvlp, 0);
2887 2905
2888 2906 free(ostat);
2889 2907
2890 2908 if (error) {
2891 2909 bam_error(_("failed to unpack stat data: %s: %s\n"),
2892 2910 path, strerror(error));
2893 2911 walk_arg.old_nvlp = NULL;
2894 2912 goto out_err;
2895 2913 } else {
2896 2914 return;
2897 2915 }
2898 2916
2899 2917 out_err:
2900 2918 if (fd != -1)
2901 2919 (void) close(fd);
2902 2920 set_dir_flag(NEED_UPDATE);
2903 2921 }
2904 2922
2905 2923 /* Best effort stale entry removal */
2906 2924 static void
2907 2925 delete_stale(char *file)
2908 2926 {
2909 2927 char path[PATH_MAX];
2910 2928 struct stat sb;
2911 2929
2912 2930 (void) snprintf(path, sizeof (path), "%s/%s", get_cachedir(), file);
2913 2931 if (!bam_check && stat(path, &sb) == 0) {
2914 2932 if (sb.st_mode & S_IFDIR)
2915 2933 (void) rmdir_r(path);
2916 2934 else
2917 2935 (void) unlink(path);
2918 2936
2919 2937 set_dir_flag(NEED_UPDATE | NO_EXTEND);
2920 2938 }
2921 2939 }
2922 2940
2923 2941 /*
2924 2942 * Checks if a file in the current (old) archive has
2925 2943 * been deleted from the root filesystem. This is needed for
2926 2944 * software like Trusted Extensions (TX) that switch early
2927 2945 * in boot based on presence/absence of a kernel module.
2928 2946 */
2929 2947 static void
2930 2948 check4stale(char *root)
2931 2949 {
2932 2950 nvpair_t *nvp;
2933 2951 nvlist_t *nvlp;
2934 2952 char *file;
2935 2953 char path[PATH_MAX];
2936 2954
2937 2955 /*
2938 2956 * Skip stale file check during smf check
2939 2957 */
2940 2958 if (bam_smf_check)
2941 2959 return;
2942 2960
2943 2961 /*
2944 2962 * If we need to (re)create the cache, there's no need to check for
2945 2963 * stale files
2946 2964 */
2947 2965 if (is_flag_on(NEED_CACHE_DIR))
2948 2966 return;
2949 2967
2950 2968 /* Nothing to do if no old stats */
2951 2969 if ((nvlp = walk_arg.old_nvlp) == NULL)
2952 2970 return;
2953 2971
2954 2972 for (nvp = nvlist_next_nvpair(nvlp, NULL); nvp;
2955 2973 nvp = nvlist_next_nvpair(nvlp, nvp)) {
2956 2974 file = nvpair_name(nvp);
2957 2975 if (file == NULL)
2958 2976 continue;
2959 2977 (void) snprintf(path, sizeof (path), "%s/%s",
2960 2978 root, file);
2961 2979 if (access(path, F_OK) < 0) {
2962 2980 if (bam_verbose)
2963 2981 bam_print(_(" stale %s\n"), path);
2964 2982
2965 2983 if (is_flag_on(IS_SPARC_TARGET)) {
2966 2984 set_dir_flag(NEED_UPDATE);
2967 2985 } else {
2968 2986 if (has_cachedir())
2969 2987 delete_stale(file);
2970 2988 }
2971 2989 }
2972 2990 }
2973 2991 }
2974 2992
2975 2993 static void
2976 2994 create_newstat(void)
2977 2995 {
2978 2996 int error;
2979 2997
2980 2998 error = nvlist_alloc(&walk_arg.new_nvlp, NV_UNIQUE_NAME, 0);
2981 2999 if (error) {
2982 3000 /*
2983 3001 * Not fatal - we can still create archive
2984 3002 */
2985 3003 walk_arg.new_nvlp = NULL;
2986 3004 bam_error(_("failed to create stat data: %s\n"),
2987 3005 strerror(error));
2988 3006 }
2989 3007 }
2990 3008
2991 3009 static int
2992 3010 walk_list(char *root, filelist_t *flistp)
2993 3011 {
2994 3012 char path[PATH_MAX];
2995 3013 line_t *lp;
2996 3014
2997 3015 for (lp = flistp->head; lp; lp = lp->next) {
2998 3016 /*
2999 3017 * Don't follow symlinks. A symlink must refer to
3000 3018 * a file that would appear in the archive through
3001 3019 * a direct reference. This matches the archive
3002 3020 * construction behavior.
3003 3021 */
3004 3022 (void) snprintf(path, sizeof (path), "%s%s", root, lp->line);
3005 3023 if (nftw(path, cmpstat, 20, FTW_PHYS) == -1) {
3006 3024 if (is_flag_on(UPDATE_ERROR))
3007 3025 return (BAM_ERROR);
3008 3026 /*
3009 3027 * Some files may not exist.
3010 3028 * For example: etc/rtc_config on a x86 diskless system
3011 3029 * Emit verbose message only
3012 3030 */
3013 3031 if (bam_verbose)
3014 3032 bam_print(_("cannot find: %s: %s\n"),
3015 3033 path, strerror(errno));
3016 3034 }
3017 3035 }
3018 3036
3019 3037 return (BAM_SUCCESS);
3020 3038 }
3021 3039
3022 3040 /*
3023 3041 * Update the timestamp file.
3024 3042 */
3025 3043 static void
3026 3044 update_timestamp(char *root)
3027 3045 {
3028 3046 char timestamp_path[PATH_MAX];
3029 3047
3030 3048 /* this path length has already been checked in check_flags_and_files */
3031 3049 (void) snprintf(timestamp_path, sizeof (timestamp_path), "%s%s", root,
3032 3050 FILE_STAT_TIMESTAMP);
3033 3051
3034 3052 /*
3035 3053 * recreate the timestamp file. Since an outdated or absent timestamp
3036 3054 * file translates in a complete rebuild of the archive cache, notify
3037 3055 * the user of the performance issue.
3038 3056 */
3039 3057 if (creat(timestamp_path, FILE_STAT_MODE) < 0) {
3040 3058 bam_error(_("failed to open file: %s: %s\n"), timestamp_path,
3041 3059 strerror(errno));
3042 3060 bam_error(_("failed to update the timestamp file, next"
3043 3061 " archive update may experience reduced performance\n"));
3044 3062 }
3045 3063 }
3046 3064
3047 3065
3048 3066 static void
3049 3067 savenew(char *root)
3050 3068 {
3051 3069 char path[PATH_MAX];
3052 3070 char path2[PATH_MAX];
3053 3071 size_t sz;
3054 3072 char *nstat;
3055 3073 int fd, wrote, error;
3056 3074
3057 3075 nstat = NULL;
3058 3076 sz = 0;
3059 3077 error = nvlist_pack(walk_arg.new_nvlp, &nstat, &sz,
3060 3078 NV_ENCODE_XDR, 0);
3061 3079 if (error) {
3062 3080 bam_error(_("failed to pack stat data: %s\n"),
3063 3081 strerror(error));
3064 3082 return;
3065 3083 }
3066 3084
3067 3085 (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT_TMP);
3068 3086 fd = open(path, O_RDWR|O_CREAT|O_TRUNC, FILE_STAT_MODE);
3069 3087 if (fd == -1) {
3070 3088 bam_error(_("failed to open file: %s: %s\n"), path,
3071 3089 strerror(errno));
3072 3090 free(nstat);
3073 3091 return;
3074 3092 }
3075 3093 wrote = write(fd, nstat, sz);
3076 3094 if (wrote != sz) {
3077 3095 bam_error(_("write to file failed: %s: %s\n"), path,
3078 3096 strerror(errno));
3079 3097 (void) close(fd);
3080 3098 free(nstat);
3081 3099 return;
3082 3100 }
3083 3101 (void) close(fd);
3084 3102 free(nstat);
3085 3103
3086 3104 (void) snprintf(path2, sizeof (path2), "%s%s", root, FILE_STAT);
3087 3105 if (rename(path, path2) != 0) {
3088 3106 bam_error(_("rename to file failed: %s: %s\n"), path2,
3089 3107 strerror(errno));
3090 3108 }
3091 3109 }
3092 3110
3093 3111 #define init_walk_args() bzero(&walk_arg, sizeof (walk_arg))
3094 3112
3095 3113 static void
3096 3114 clear_walk_args(void)
3097 3115 {
3098 3116 nvlist_free(walk_arg.old_nvlp);
3099 3117 nvlist_free(walk_arg.new_nvlp);
3100 3118 if (walk_arg.sparcfile)
3101 3119 (void) fclose(walk_arg.sparcfile);
3102 3120 walk_arg.old_nvlp = NULL;
3103 3121 walk_arg.new_nvlp = NULL;
3104 3122 walk_arg.sparcfile = NULL;
3105 3123 }
3106 3124
3107 3125 /*
3108 3126 * Returns:
3109 3127 * 0 - no update necessary
3110 3128 * 1 - update required.
3111 3129 * BAM_ERROR (-1) - An error occurred
3112 3130 *
3113 3131 * Special handling for check (-n):
3114 3132 * ================================
3115 3133 * The check (-n) option produces parseable output.
3116 3134 * To do this, we suppress all stdout messages unrelated
3117 3135 * to out of sync files.
3118 3136 * All stderr messages are still printed though.
3119 3137 *
3120 3138 */
3121 3139 static int
3122 3140 update_required(char *root)
3123 3141 {
3124 3142 struct stat sb;
3125 3143 char path[PATH_MAX];
3126 3144 filelist_t flist;
3127 3145 filelist_t *flistp = &flist;
3128 3146 int ret;
3129 3147
3130 3148 flistp->head = flistp->tail = NULL;
3131 3149
3132 3150 if (is_sparc())
3133 3151 set_flag(IS_SPARC_TARGET);
3134 3152
3135 3153 /*
3136 3154 * Check if cache directories and archives are present
3137 3155 */
3138 3156
3139 3157 ret = check_flags_and_files(root);
3140 3158 if (ret < 0)
3141 3159 return (BAM_ERROR);
3142 3160
3143 3161 /*
3144 3162 * In certain deployment scenarios, filestat may not
3145 3163 * exist. Do not stop the boot process, but trigger an update
3146 3164 * of the archives (which will recreate filestat.ramdisk).
3147 3165 */
3148 3166 if (bam_smf_check) {
3149 3167 (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT);
3150 3168 if (stat(path, &sb) != 0) {
3151 3169 (void) creat(NEED_UPDATE_FILE, 0644);
3152 3170 return (0);
3153 3171 }
3154 3172 }
3155 3173
3156 3174 getoldstat(root);
3157 3175
3158 3176 /*
3159 3177 * Check if the archive contains files that are no longer
3160 3178 * present on the root filesystem.
3161 3179 */
3162 3180 check4stale(root);
3163 3181
3164 3182 /*
3165 3183 * read list of files
3166 3184 */
3167 3185 if (read_list(root, flistp) != BAM_SUCCESS) {
3168 3186 clear_walk_args();
3169 3187 return (BAM_ERROR);
3170 3188 }
3171 3189
3172 3190 assert(flistp->head && flistp->tail);
3173 3191
3174 3192 /*
3175 3193 * At this point either the update is required
3176 3194 * or the decision is pending. In either case
3177 3195 * we need to create new stat nvlist
3178 3196 */
3179 3197 create_newstat();
3180 3198 /*
3181 3199 * This walk does 2 things:
3182 3200 * - gets new stat data for every file
3183 3201 * - (optional) compare old and new stat data
3184 3202 */
3185 3203 ret = walk_list(root, &flist);
3186 3204
3187 3205 /* done with the file list */
3188 3206 filelist_free(flistp);
3189 3207
3190 3208 /* something went wrong */
3191 3209
3192 3210 if (ret == BAM_ERROR) {
3193 3211 bam_error(_("Failed to gather cache files, archives "
3194 3212 "generation aborted\n"));
3195 3213 return (BAM_ERROR);
3196 3214 }
3197 3215
3198 3216 if (walk_arg.new_nvlp == NULL) {
3199 3217 if (walk_arg.sparcfile != NULL)
3200 3218 (void) fclose(walk_arg.sparcfile);
3201 3219 bam_error(_("cannot create new stat data\n"));
3202 3220 }
3203 3221
3204 3222 /* If nothing was updated, discard newstat. */
3205 3223
3206 3224 if (!is_dir_flag_on(NEED_UPDATE)) {
3207 3225 clear_walk_args();
3208 3226 return (0);
3209 3227 }
3210 3228
3211 3229 if (walk_arg.sparcfile != NULL)
3212 3230 (void) fclose(walk_arg.sparcfile);
3213 3231
3214 3232 return (1);
3215 3233 }
3216 3234
3217 3235 static int
3218 3236 flushfs(char *root)
3219 3237 {
3220 3238 char cmd[PATH_MAX + 30];
3221 3239
3222 3240 (void) snprintf(cmd, sizeof (cmd), "%s -f \"%s\" 2>/dev/null",
3223 3241 LOCKFS_PATH, root);
3224 3242
3225 3243 return (exec_cmd(cmd, NULL));
3226 3244 }
3227 3245
3228 3246 static int
3229 3247 do_archive_copy(char *source, char *dest)
3230 3248 {
3231 3249
3232 3250 sync();
3233 3251
3234 3252 /* the equivalent of mv archive-new-$pid boot_archive */
3235 3253 if (rename(source, dest) != 0) {
3236 3254 (void) unlink(source);
3237 3255 return (BAM_ERROR);
3238 3256 }
3239 3257
3240 3258 if (flushfs(bam_root) != 0)
3241 3259 sync();
3242 3260
3243 3261 return (BAM_SUCCESS);
3244 3262 }
3245 3263
3246 3264 static int
3247 3265 check_cmdline(filelist_t flist)
3248 3266 {
3249 3267 line_t *lp;
3250 3268
3251 3269 for (lp = flist.head; lp; lp = lp->next) {
3252 3270 if (strstr(lp->line, "Error:") != NULL ||
3253 3271 strstr(lp->line, "Inode number overflow") != NULL) {
3254 3272 (void) fprintf(stderr, "%s\n", lp->line);
3255 3273 return (BAM_ERROR);
3256 3274 }
3257 3275 }
3258 3276
3259 3277 return (BAM_SUCCESS);
3260 3278 }
3261 3279
3262 3280 static void
3263 3281 dump_errormsg(filelist_t flist)
3264 3282 {
3265 3283 line_t *lp;
3266 3284
3267 3285 for (lp = flist.head; lp; lp = lp->next)
3268 3286 (void) fprintf(stderr, "%s\n", lp->line);
3269 3287 }
3270 3288
3271 3289 static int
3272 3290 check_archive(char *dest)
3273 3291 {
3274 3292 struct stat sb;
3275 3293
3276 3294 if (stat(dest, &sb) != 0 || !S_ISREG(sb.st_mode) ||
3277 3295 sb.st_size < 10000) {
3278 3296 bam_error(_("archive file %s not generated correctly\n"), dest);
3279 3297 (void) unlink(dest);
3280 3298 return (BAM_ERROR);
3281 3299 }
3282 3300
3283 3301 return (BAM_SUCCESS);
3284 3302 }
3285 3303
3286 3304 static boolean_t
3287 3305 is_be(char *root)
3288 3306 {
3289 3307 zfs_handle_t *zhp;
3290 3308 libzfs_handle_t *hdl;
3291 3309 be_node_list_t *be_nodes = NULL;
3292 3310 be_node_list_t *cur_be;
3293 3311 boolean_t be_exist = B_FALSE;
3294 3312 char ds_path[ZFS_MAX_DATASET_NAME_LEN];
3295 3313
3296 3314 if (!is_zfs(root))
3297 3315 return (B_FALSE);
3298 3316 /*
3299 3317 * Get dataset for mountpoint
3300 3318 */
3301 3319 if ((hdl = libzfs_init()) == NULL)
3302 3320 return (B_FALSE);
3303 3321
3304 3322 if ((zhp = zfs_path_to_zhandle(hdl, root,
3305 3323 ZFS_TYPE_FILESYSTEM)) == NULL) {
3306 3324 libzfs_fini(hdl);
3307 3325 return (B_FALSE);
3308 3326 }
3309 3327
3310 3328 (void) strlcpy(ds_path, zfs_get_name(zhp), sizeof (ds_path));
3311 3329
3312 3330 /*
3313 3331 * Check if the current dataset is BE
3314 3332 */
3315 3333 if (be_list(NULL, &be_nodes, BE_LIST_DEFAULT) == BE_SUCCESS) {
3316 3334 for (cur_be = be_nodes; cur_be != NULL;
3317 3335 cur_be = cur_be->be_next_node) {
3318 3336
3319 3337 /*
3320 3338 * Because we guarantee that cur_be->be_root_ds
3321 3339 * is null-terminated by internal data structure,
3322 3340 * we can safely use strcmp()
3323 3341 */
3324 3342 if (strcmp(ds_path, cur_be->be_root_ds) == 0) {
3325 3343 be_exist = B_TRUE;
3326 3344 break;
3327 3345 }
3328 3346 }
3329 3347 be_free_list(be_nodes);
3330 3348 }
3331 3349 zfs_close(zhp);
3332 3350 libzfs_fini(hdl);
3333 3351
3334 3352 return (be_exist);
3335 3353 }
3336 3354
3337 3355 /*
3338 3356 * Returns B_TRUE if mkiso is in the expected PATH and should be used,
3339 3357 * B_FALSE otherwise
3340 3358 */
3341 3359 static boolean_t
3342 3360 use_mkisofs()
3343 3361 {
3344 3362 scf_simple_prop_t *prop;
3345 3363 char *format = NULL;
3346 3364 boolean_t ret;
3347 3365
3348 3366 /* Check whether the mkisofs binary is in the expected location */
3349 3367 if (access(MKISOFS_PATH, X_OK) != 0) {
3350 3368 if (bam_verbose)
3351 3369 bam_print("mkisofs not found\n");
3352 3370 return (B_FALSE);
3353 3371 }
3354 3372
3355 3373 if (bam_format == BAM_FORMAT_HSFS) {
3356 3374 if (bam_verbose)
3357 3375 bam_print("-F specified HSFS");
3358 3376 return (B_TRUE);
3359 3377 }
3360 3378
3361 3379 /* If working on an alt-root, do not use HSFS unless asked via -F */
3362 3380 if (bam_alt_root)
3363 3381 return (B_FALSE);
3364 3382
3365 3383 /*
3366 3384 * Then check that the system/boot-archive config/format property
3367 3385 * is "hsfs" or empty.
3368 3386 */
3369 3387 if ((prop = scf_simple_prop_get(NULL, BOOT_ARCHIVE_FMRI, SCF_PG_CONFIG,
3370 3388 SCF_PROPERTY_FORMAT)) == NULL) {
3371 3389 /* Could not find property, use mkisofs */
3372 3390 if (bam_verbose) {
3373 3391 bam_print(
3374 3392 "%s does not have %s/%s property, using mkisofs\n",
3375 3393 BOOT_ARCHIVE_FMRI, SCF_PG_CONFIG,
3376 3394 SCF_PROPERTY_FORMAT);
3377 3395 }
3378 3396 return (B_TRUE);
3379 3397 }
3380 3398 if (scf_simple_prop_numvalues(prop) < 0 ||
3381 3399 (format = scf_simple_prop_next_astring(prop)) == NULL)
3382 3400 ret = B_TRUE;
3383 3401 else
3384 3402 ret = strcmp(format, "hsfs") == 0 ? B_TRUE : B_FALSE;
3385 3403 if (bam_verbose) {
3386 3404 if (ret)
3387 3405 bam_print("Creating hsfs boot archive\n");
3388 3406 else
3389 3407 bam_print("Creating %s boot archive\n", format);
3390 3408 }
3391 3409 scf_simple_prop_free(prop);
3392 3410 return (ret);
3393 3411 }
3394 3412
3395 3413 #define MKISO_PARAMS " -quiet -graft-points -dlrDJN -relaxed-filenames "
3396 3414
3397 3415 static int
3398 3416 create_sparc_archive(char *archive, char *tempname, char *bootblk, char *list)
3399 3417 {
3400 3418 int ret;
3401 3419 char cmdline[3 * PATH_MAX + 64];
3402 3420 filelist_t flist = {0};
3403 3421 const char *func = "create_sparc_archive()";
3404 3422
3405 3423 if (access(bootblk, R_OK) == 1) {
3406 3424 bam_error(_("unable to access bootblk file : %s\n"), bootblk);
3407 3425 return (BAM_ERROR);
3408 3426 }
3409 3427
3410 3428 /*
3411 3429 * Prepare mkisofs command line and execute it
3412 3430 */
3413 3431 (void) snprintf(cmdline, sizeof (cmdline), "%s %s -G %s -o \"%s\" "
3414 3432 "-path-list \"%s\" 2>&1", MKISOFS_PATH, MKISO_PARAMS, bootblk,
3415 3433 tempname, list);
3416 3434
3417 3435 BAM_DPRINTF(("%s: executing: %s\n", func, cmdline));
3418 3436
3419 3437 ret = exec_cmd(cmdline, &flist);
3420 3438 if (ret != 0 || check_cmdline(flist) == BAM_ERROR) {
3421 3439 dump_errormsg(flist);
3422 3440 goto out_err;
3423 3441 }
3424 3442
3425 3443 filelist_free(&flist);
3426 3444
3427 3445 /*
3428 3446 * Prepare dd command line to copy the bootblk on the new archive and
3429 3447 * execute it
3430 3448 */
3431 3449 (void) snprintf(cmdline, sizeof (cmdline), "%s if=\"%s\" of=\"%s\""
3432 3450 " bs=1b oseek=1 count=15 conv=notrunc conv=sync 2>&1", DD_PATH_USR,
3433 3451 bootblk, tempname);
3434 3452
3435 3453 BAM_DPRINTF(("%s: executing: %s\n", func, cmdline));
3436 3454
3437 3455 ret = exec_cmd(cmdline, &flist);
3438 3456 if (ret != 0 || check_cmdline(flist) == BAM_ERROR)
3439 3457 goto out_err;
3440 3458
3441 3459 filelist_free(&flist);
3442 3460
3443 3461 /* Did we get a valid archive ? */
3444 3462 if (check_archive(tempname) == BAM_ERROR)
3445 3463 return (BAM_ERROR);
3446 3464
3447 3465 return (do_archive_copy(tempname, archive));
3448 3466
3449 3467 out_err:
3450 3468 filelist_free(&flist);
3451 3469 bam_error(_("boot-archive creation FAILED, command: '%s'\n"), cmdline);
3452 3470 (void) unlink(tempname);
3453 3471 return (BAM_ERROR);
3454 3472 }
3455 3473
3456 3474 static unsigned int
3457 3475 from_733(unsigned char *s)
3458 3476 {
3459 3477 int i;
3460 3478 unsigned int ret = 0;
3461 3479
3462 3480 for (i = 0; i < 4; i++)
3463 3481 ret |= s[i] << (8 * i);
3464 3482
3465 3483 return (ret);
3466 3484 }
3467 3485
3468 3486 static void
3469 3487 to_733(unsigned char *s, unsigned int val)
3470 3488 {
3471 3489 int i;
3472 3490
3473 3491 for (i = 0; i < 4; i++)
3474 3492 s[i] = s[7-i] = (val >> (8 * i)) & 0xFF;
3475 3493 }
3476 3494
3477 3495 /*
3478 3496 * creates sha1 hash of archive
3479 3497 */
3480 3498 static int
3481 3499 digest_archive(const char *archive)
3482 3500 {
3483 3501 char *archive_hash;
3484 3502 char *hash;
3485 3503 int ret;
3486 3504 FILE *fp;
3487 3505
3488 3506 (void) asprintf(&archive_hash, "%s.hash", archive);
3489 3507 if (archive_hash == NULL)
3490 3508 return (BAM_ERROR);
3491 3509
3492 3510 if ((ret = bootadm_digest(archive, &hash)) == BAM_ERROR) {
3493 3511 free(archive_hash);
3494 3512 return (ret);
3495 3513 }
3496 3514
3497 3515 fp = fopen(archive_hash, "w");
3498 3516 if (fp == NULL) {
3499 3517 free(archive_hash);
3500 3518 free(hash);
3501 3519 return (BAM_ERROR);
3502 3520 }
3503 3521
3504 3522 (void) fprintf(fp, "%s\n", hash);
3505 3523 (void) fclose(fp);
3506 3524 free(hash);
3507 3525 free(archive_hash);
3508 3526 return (BAM_SUCCESS);
3509 3527 }
3510 3528
3511 3529 /*
3512 3530 * Extends the current boot archive without recreating it from scratch
3513 3531 */
3514 3532 static int
3515 3533 extend_iso_archive(char *archive, char *tempname, char *update_dir)
3516 3534 {
3517 3535 int fd = -1, newfd = -1, ret, i;
3518 3536 int next_session = 0, new_size = 0;
3519 3537 char cmdline[3 * PATH_MAX + 64];
3520 3538 const char *func = "extend_iso_archive()";
3521 3539 filelist_t flist = {0};
3522 3540 struct iso_pdesc saved_desc[MAX_IVDs];
3523 3541
3524 3542 fd = open(archive, O_RDWR);
3525 3543 if (fd == -1) {
3526 3544 if (bam_verbose)
3527 3545 bam_error(_("failed to open file: %s: %s\n"),
3528 3546 archive, strerror(errno));
3529 3547 goto out_err;
3530 3548 }
3531 3549
3532 3550 /*
3533 3551 * A partial read is likely due to a corrupted file
3534 3552 */
3535 3553 ret = pread64(fd, saved_desc, sizeof (saved_desc),
3536 3554 VOLDESC_OFF * CD_BLOCK);
3537 3555 if (ret != sizeof (saved_desc)) {
3538 3556 if (bam_verbose)
3539 3557 bam_error(_("read failed for file: %s: %s\n"),
3540 3558 archive, strerror(errno));
3541 3559 goto out_err;
3542 3560 }
3543 3561
3544 3562 if (memcmp(saved_desc[0].type, "\1CD001", 6)) {
3545 3563 if (bam_verbose)
3546 3564 bam_error(_("iso descriptor signature for %s is "
3547 3565 "invalid\n"), archive);
3548 3566 goto out_err;
3549 3567 }
3550 3568
3551 3569 /*
3552 3570 * Read primary descriptor and locate next_session offset (it should
3553 3571 * point to the end of the archive)
3554 3572 */
3555 3573 next_session = P2ROUNDUP(from_733(saved_desc[0].volume_space_size), 16);
3556 3574
3557 3575 (void) snprintf(cmdline, sizeof (cmdline), "%s -C 16,%d -M %s %s -o \""
3558 3576 "%s\" \"%s\" 2>&1", MKISOFS_PATH, next_session, archive,
3559 3577 MKISO_PARAMS, tempname, update_dir);
3560 3578
3561 3579 BAM_DPRINTF(("%s: executing: %s\n", func, cmdline));
3562 3580
3563 3581 ret = exec_cmd(cmdline, &flist);
3564 3582 if (ret != 0 || check_cmdline(flist) == BAM_ERROR) {
3565 3583 if (bam_verbose) {
3566 3584 bam_error(_("Command '%s' failed while generating "
3567 3585 "multisession archive\n"), cmdline);
3568 3586 dump_errormsg(flist);
3569 3587 }
3570 3588 goto out_flist_err;
3571 3589 }
3572 3590 filelist_free(&flist);
3573 3591
3574 3592 newfd = open(tempname, O_RDONLY);
3575 3593 if (newfd == -1) {
3576 3594 if (bam_verbose)
3577 3595 bam_error(_("failed to open file: %s: %s\n"),
3578 3596 archive, strerror(errno));
3579 3597 goto out_err;
3580 3598 }
3581 3599
3582 3600 ret = pread64(newfd, saved_desc, sizeof (saved_desc),
3583 3601 VOLDESC_OFF * CD_BLOCK);
3584 3602 if (ret != sizeof (saved_desc)) {
3585 3603 if (bam_verbose)
3586 3604 bam_error(_("read failed for file: %s: %s\n"),
3587 3605 archive, strerror(errno));
3588 3606 goto out_err;
3589 3607 }
3590 3608
3591 3609 if (memcmp(saved_desc[0].type, "\1CD001", 6)) {
3592 3610 if (bam_verbose)
3593 3611 bam_error(_("iso descriptor signature for %s is "
3594 3612 "invalid\n"), archive);
3595 3613 goto out_err;
3596 3614 }
3597 3615
3598 3616 new_size = from_733(saved_desc[0].volume_space_size) + next_session;
3599 3617 to_733(saved_desc[0].volume_space_size, new_size);
3600 3618
3601 3619 for (i = 1; i < MAX_IVDs; i++) {
3602 3620 if (saved_desc[i].type[0] == (unsigned char)255)
3603 3621 break;
3604 3622 if (memcmp(saved_desc[i].id, "CD001", 5))
3605 3623 break;
3606 3624
3607 3625 if (bam_verbose)
3608 3626 bam_print("%s: Updating descriptor entry [%d]\n", func,
3609 3627 i);
3610 3628
3611 3629 to_733(saved_desc[i].volume_space_size, new_size);
3612 3630 }
3613 3631
3614 3632 ret = pwrite64(fd, saved_desc, DVD_BLOCK, VOLDESC_OFF*CD_BLOCK);
3615 3633 if (ret != DVD_BLOCK) {
3616 3634 if (bam_verbose)
3617 3635 bam_error(_("write to file failed: %s: %s\n"),
3618 3636 archive, strerror(errno));
3619 3637 goto out_err;
3620 3638 }
3621 3639 (void) close(newfd);
3622 3640 newfd = -1;
3623 3641
3624 3642 ret = fsync(fd);
3625 3643 if (ret != 0)
3626 3644 sync();
3627 3645
3628 3646 ret = close(fd);
3629 3647 if (ret != 0) {
3630 3648 if (bam_verbose)
3631 3649 bam_error(_("failed to close file: %s: %s\n"),
3632 3650 archive, strerror(errno));
3633 3651 return (BAM_ERROR);
3634 3652 }
3635 3653 fd = -1;
3636 3654
3637 3655 (void) snprintf(cmdline, sizeof (cmdline), "%s if=%s of=%s bs=32k "
3638 3656 "seek=%d conv=sync 2>&1", DD_PATH_USR, tempname, archive,
3639 3657 (next_session/16));
3640 3658
3641 3659 BAM_DPRINTF(("%s: executing: %s\n", func, cmdline));
3642 3660
3643 3661 ret = exec_cmd(cmdline, &flist);
3644 3662 if (ret != 0 || check_cmdline(flist) == BAM_ERROR) {
3645 3663 if (bam_verbose)
3646 3664 bam_error(_("Command '%s' failed while generating "
3647 3665 "multisession archive\n"), cmdline);
3648 3666 goto out_flist_err;
3649 3667 }
3650 3668 filelist_free(&flist);
3651 3669
3652 3670 (void) unlink(tempname);
3653 3671
3654 3672 if (digest_archive(archive) == BAM_ERROR && bam_verbose)
3655 3673 bam_print("boot archive hashing failed\n");
3656 3674
3657 3675 if (flushfs(bam_root) != 0)
3658 3676 sync();
3659 3677
3660 3678 if (bam_verbose)
3661 3679 bam_print("boot archive updated successfully\n");
3662 3680
3663 3681 return (BAM_SUCCESS);
3664 3682
3665 3683 out_flist_err:
3666 3684 filelist_free(&flist);
3667 3685 out_err:
3668 3686 if (fd != -1)
3669 3687 (void) close(fd);
3670 3688 if (newfd != -1)
3671 3689 (void) close(newfd);
3672 3690 return (BAM_ERROR);
3673 3691 }
3674 3692
3675 3693 static int
3676 3694 create_x86_archive(char *archive, char *tempname, char *update_dir)
3677 3695 {
3678 3696 int ret;
3679 3697 char cmdline[3 * PATH_MAX + 64];
3680 3698 filelist_t flist = {0};
3681 3699 const char *func = "create_x86_archive()";
3682 3700
3683 3701 (void) snprintf(cmdline, sizeof (cmdline), "%s %s -o \"%s\" \"%s\" "
3684 3702 "2>&1", MKISOFS_PATH, MKISO_PARAMS, tempname, update_dir);
3685 3703
3686 3704 BAM_DPRINTF(("%s: executing: %s\n", func, cmdline));
3687 3705
3688 3706 ret = exec_cmd(cmdline, &flist);
3689 3707 if (ret != 0 || check_cmdline(flist) == BAM_ERROR) {
3690 3708 bam_error(_("boot-archive creation FAILED, command: '%s'\n"),
3691 3709 cmdline);
3692 3710 dump_errormsg(flist);
3693 3711 filelist_free(&flist);
3694 3712 (void) unlink(tempname);
3695 3713 return (BAM_ERROR);
3696 3714 }
3697 3715
3698 3716 filelist_free(&flist);
3699 3717
3700 3718 if (check_archive(tempname) == BAM_ERROR)
3701 3719 return (BAM_ERROR);
3702 3720
3703 3721 return (do_archive_copy(tempname, archive));
3704 3722 }
3705 3723
3706 3724 static int
3707 3725 mkisofs_archive(char *root)
3708 3726 {
3709 3727 int ret;
3710 3728 char suffix[20];
3711 3729 char temp[PATH_MAX];
3712 3730 char bootblk[PATH_MAX];
3713 3731 char boot_archive[PATH_MAX];
3714 3732
3715 3733 ret = snprintf(suffix, sizeof (suffix), "/archive-new-%d", getpid());
3716 3734 if (ret >= sizeof (suffix))
3717 3735 goto out_path_err;
3718 3736
3719 3737 ret = build_path(temp, sizeof (temp), root, ARCHIVE_PREFIX, suffix);
3720 3738
3721 3739 if (ret >= sizeof (temp))
3722 3740 goto out_path_err;
3723 3741
3724 3742 ret = build_path(boot_archive, sizeof (boot_archive), root,
3725 3743 ARCHIVE_PREFIX, ARCHIVE_SUFFIX);
3726 3744
3727 3745 if (ret >= sizeof (boot_archive))
3728 3746 goto out_path_err;
3729 3747
3730 3748 bam_print("updating %s (HSFS)\n",
3731 3749 boot_archive[1] == '/' ? boot_archive + 1 : boot_archive);
3732 3750
3733 3751 if (is_flag_on(IS_SPARC_TARGET)) {
3734 3752 ret = snprintf(bootblk, sizeof (bootblk),
3735 3753 "%s/platform/%s/lib/fs/hsfs/bootblk", root, get_machine());
3736 3754 if (ret >= sizeof (bootblk))
3737 3755 goto out_path_err;
3738 3756
3739 3757 ret = create_sparc_archive(boot_archive, temp, bootblk,
3740 3758 get_cachedir());
3741 3759 } else {
3742 3760 if (!is_dir_flag_on(NO_EXTEND)) {
3743 3761 if (bam_verbose)
3744 3762 bam_print("Attempting to extend x86 archive: "
3745 3763 "%s\n", boot_archive);
3746 3764
3747 3765 ret = extend_iso_archive(boot_archive, temp,
3748 3766 get_updatedir());
3749 3767 if (ret == BAM_SUCCESS) {
3750 3768 if (bam_verbose)
3751 3769 bam_print("Successfully extended %s\n",
3752 3770 boot_archive);
3753 3771
3754 3772 (void) rmdir_r(get_updatedir());
3755 3773 return (BAM_SUCCESS);
3756 3774 }
3757 3775 }
3758 3776 /*
3759 3777 * The boot archive will be recreated from scratch. We get here
3760 3778 * if at least one of these conditions is true:
3761 3779 * - bootadm was called without the -e switch
3762 3780 * - the archive (or the archive cache) doesn't exist
3763 3781 * - archive size is bigger than BA_SIZE_MAX
3764 3782 * - more than COUNT_MAX files need to be updated
3765 3783 * - an error occourred either populating the /updates directory
3766 3784 * or extend_iso_archive() failed
3767 3785 */
3768 3786 if (bam_verbose)
3769 3787 bam_print("Unable to extend %s... rebuilding archive\n",
3770 3788 boot_archive);
3771 3789
3772 3790 if (get_updatedir()[0] != '\0')
3773 3791 (void) rmdir_r(get_updatedir());
3774 3792
3775 3793
3776 3794 ret = create_x86_archive(boot_archive, temp,
3777 3795 get_cachedir());
3778 3796 }
3779 3797
3780 3798 if (digest_archive(boot_archive) == BAM_ERROR && bam_verbose)
3781 3799 bam_print("boot archive hashing failed\n");
3782 3800
3783 3801 if (ret == BAM_SUCCESS && bam_verbose)
↓ open down ↓ |
1312 lines elided |
↑ open up ↑ |
3784 3802 bam_print("Successfully created %s\n", boot_archive);
3785 3803
3786 3804 return (ret);
3787 3805
3788 3806 out_path_err:
3789 3807 bam_error(_("unable to create path on mountpoint %s, path too long\n"),
3790 3808 root);
3791 3809 return (BAM_ERROR);
3792 3810 }
3793 3811
3812 +static int
3813 +assemble_systemfile(char *infilename, char *outfilename)
3814 +{
3815 + char buf[BUFSIZ];
3816 + FILE *infile, *outfile;
3817 + size_t n;
3818 +
3819 + if ((infile = fopen(infilename, "r")) == NULL) {
3820 + bam_error(_("failed to open file: %s: %s\n"), infilename,
3821 + strerror(errno));
3822 + return (BAM_ERROR);
3823 + }
3824 +
3825 + if ((outfile = fopen(outfilename, "a")) == NULL) {
3826 + bam_error(_("failed to open file: %s: %s\n"), outfilename,
3827 + strerror(errno));
3828 + (void) fclose(infile);
3829 + return (BAM_ERROR);
3830 + }
3831 +
3832 + while ((n = fread(buf, 1, sizeof (buf), infile)) > 0) {
3833 + if (fwrite(buf, 1, n, outfile) != n) {
3834 + bam_error(_("failed to write file: %s: %s\n"),
3835 + outfilename, strerror(errno));
3836 + (void) fclose(infile);
3837 + (void) fclose(outfile);
3838 + return (BAM_ERROR);
3839 + }
3840 + }
3841 +
3842 + (void) fclose(infile);
3843 + (void) fclose(outfile);
3844 +
3845 + return (BAM_SUCCESS);
3846 +}
3847 +
3848 +/*
3849 + * Concatenate all files (except those starting with a dot)
3850 + * from /etc/system.d directory into a single /etc/system.d/.self-assembly
3851 + * file. The kernel reads it before /etc/system file.
3852 + */
3794 3853 static error_t
3854 +build_etc_system_dir(char *root)
3855 +{
3856 + struct dirent **filelist;
3857 + char path[PATH_MAX], tmpfile[PATH_MAX];
3858 + int i, files, sysfiles = 0;
3859 + int ret = BAM_SUCCESS;
3860 + struct stat st;
3861 + timespec_t times[2];
3862 +
3863 + (void) snprintf(path, sizeof (path), "%s/%s", root, ETC_SYSTEM_DIR);
3864 + (void) snprintf(self_assembly, sizeof (self_assembly),
3865 + "%s%s", root, SELF_ASSEMBLY);
3866 + (void) snprintf(tmpfile, sizeof (tmpfile), "%s.%ld",
3867 + self_assembly, (long)getpid());
3868 +
3869 + if (stat(self_assembly, &st) >= 0 && (st.st_mode & S_IFMT) == S_IFREG) {
3870 + times[0] = times[1] = st.st_mtim;
3871 + } else {
3872 + times[1].tv_nsec = 0;
3873 + }
3874 +
3875 + if ((files = scandir(path, &filelist, NULL, alphasort)) < 0) {
3876 + /* Don't fail the update if <ROOT>/etc/system.d doesn't exist */
3877 + if (errno == ENOENT)
3878 + return (BAM_SUCCESS);
3879 + bam_error(_("can't read %s: %s\n"), path, strerror(errno));
3880 + return (BAM_ERROR);
3881 + }
3882 +
3883 + (void) unlink(tmpfile);
3884 +
3885 + for (i = 0; i < files; i++) {
3886 + char filepath[PATH_MAX];
3887 + char *fname;
3888 +
3889 + fname = filelist[i]->d_name;
3890 +
3891 + /* skip anything that starts with a dot */
3892 + if (strncmp(fname, ".", 1) == 0) {
3893 + free(filelist[i]);
3894 + continue;
3895 + }
3896 +
3897 + if (bam_verbose)
3898 + bam_print(_("/etc/system.d adding %s/%s\n"),
3899 + path, fname);
3900 +
3901 + (void) snprintf(filepath, sizeof (filepath), "%s/%s",
3902 + path, fname);
3903 +
3904 + if ((assemble_systemfile(filepath, tmpfile)) < 0) {
3905 + bam_error(_("failed to append file: %s: %s\n"),
3906 + filepath, strerror(errno));
3907 + ret = BAM_ERROR;
3908 + break;
3909 + }
3910 + sysfiles++;
3911 + }
3912 +
3913 + if (sysfiles > 0) {
3914 + if (rename(tmpfile, self_assembly) < 0) {
3915 + bam_error(_("failed to rename file: %s: %s\n"), tmpfile,
3916 + strerror(errno));
3917 + return (BAM_ERROR);
3918 + }
3919 +
3920 + /*
3921 + * Use previous attribute times to avoid
3922 + * boot archive recreation.
3923 + */
3924 + if (times[1].tv_nsec != 0 &&
3925 + utimensat(AT_FDCWD, self_assembly, times, 0) != 0) {
3926 + bam_error(_("failed to change times: %s\n"),
3927 + strerror(errno));
3928 + return (BAM_ERROR);
3929 + }
3930 + } else {
3931 + (void) unlink(tmpfile);
3932 + (void) unlink(self_assembly);
3933 + }
3934 + return (ret);
3935 +}
3936 +
3937 +static error_t
3795 3938 create_ramdisk(char *root)
3796 3939 {
3797 3940 char *cmdline, path[PATH_MAX];
3798 3941 size_t len;
3799 3942 struct stat sb;
3800 3943 int ret, status = BAM_SUCCESS;
3801 3944
3802 3945 /* If mkisofs should be used, use it to create the required archives */
3803 3946 if (use_mkisofs()) {
3804 3947 if (has_cachedir() && is_dir_flag_on(NEED_UPDATE)) {
3805 3948 ret = mkisofs_archive(root);
3806 3949 if (ret != 0)
3807 3950 status = BAM_ERROR;
3808 3951 }
3809 3952 return (status);
3810 3953 } else if (bam_format == BAM_FORMAT_HSFS) {
3811 3954 bam_error(_("cannot create hsfs archive\n"));
3812 3955 return (BAM_ERROR);
3813 3956 }
3814 3957
3815 3958 /*
3816 3959 * Else setup command args for create_ramdisk.ksh for the archive
3817 3960 * Note: we will not create hash here, CREATE_RAMDISK should create it.
3818 3961 */
3819 3962
3820 3963 (void) snprintf(path, sizeof (path), "%s/%s", root, CREATE_RAMDISK);
3821 3964 if (stat(path, &sb) != 0) {
3822 3965 bam_error(_("archive creation file not found: %s: %s\n"),
3823 3966 path, strerror(errno));
3824 3967 return (BAM_ERROR);
3825 3968 }
3826 3969
3827 3970 if (is_safe_exec(path) == BAM_ERROR)
3828 3971 return (BAM_ERROR);
3829 3972
3830 3973 len = strlen(path) + strlen(root) + 10; /* room for space + -R */
3831 3974 if (bam_alt_platform)
3832 3975 len += strlen(bam_platform) + strlen(" -p ");
3833 3976 if (bam_format != BAM_FORMAT_UNSET)
3834 3977 len += strlen(bam_formats[bam_format]) + strlen(" -f ");
3835 3978 cmdline = s_calloc(1, len);
3836 3979
3837 3980 if (bam_alt_platform) {
3838 3981 assert(strlen(root) > 1);
3839 3982 (void) snprintf(cmdline, len, "%s -p %s -R %s",
3840 3983 path, bam_platform, root);
3841 3984 /* chop off / at the end */
3842 3985 cmdline[strlen(cmdline) - 1] = '\0';
3843 3986 } else if (strlen(root) > 1) {
3844 3987 (void) snprintf(cmdline, len, "%s -R %s", path, root);
3845 3988 /* chop off / at the end */
3846 3989 cmdline[strlen(cmdline) - 1] = '\0';
3847 3990 } else
3848 3991 (void) snprintf(cmdline, len, "%s", path);
3849 3992
3850 3993 if (bam_format != BAM_FORMAT_UNSET) {
3851 3994 if (strlcat(cmdline, " -f ", len) >= len ||
3852 3995 strlcat(cmdline, bam_formats[bam_format], len) >= len) {
3853 3996 bam_error(_("boot-archive command line too long\n"));
3854 3997 free(cmdline);
3855 3998 return (BAM_ERROR);
3856 3999 }
3857 4000 }
3858 4001
3859 4002 if (exec_cmd(cmdline, NULL) != 0) {
3860 4003 bam_error(_("boot-archive creation FAILED, command: '%s'\n"),
3861 4004 cmdline);
3862 4005 free(cmdline);
3863 4006 return (BAM_ERROR);
3864 4007 }
3865 4008 free(cmdline);
3866 4009 /*
3867 4010 * The existence of the expected archives used to be
3868 4011 * verified here. This check is done in create_ramdisk as
3869 4012 * it needs to be in sync with the altroot operated upon.
3870 4013 */
3871 4014 return (BAM_SUCCESS);
3872 4015 }
3873 4016
3874 4017 /*
3875 4018 * Checks if target filesystem is on a ramdisk
3876 4019 * 1 - is miniroot
3877 4020 * 0 - is not
3878 4021 * When in doubt assume it is not a ramdisk.
3879 4022 */
3880 4023 static int
3881 4024 is_ramdisk(char *root)
3882 4025 {
3883 4026 struct extmnttab mnt;
3884 4027 FILE *fp;
3885 4028 int found;
3886 4029 char mntpt[PATH_MAX];
3887 4030 char *cp;
3888 4031
3889 4032 /*
3890 4033 * There are 3 situations where creating archive is
3891 4034 * of dubious value:
3892 4035 * - create boot_archive on a lofi-mounted boot_archive
3893 4036 * - create it on a ramdisk which is the root filesystem
3894 4037 * - create it on a ramdisk mounted somewhere else
3895 4038 * The first is not easy to detect and checking for it is not
3896 4039 * worth it.
3897 4040 * The other two conditions are handled here
3898 4041 */
3899 4042 fp = fopen(MNTTAB, "r");
3900 4043 if (fp == NULL) {
3901 4044 bam_error(_("failed to open file: %s: %s\n"),
3902 4045 MNTTAB, strerror(errno));
3903 4046 return (0);
3904 4047 }
3905 4048
3906 4049 resetmnttab(fp);
3907 4050
3908 4051 /*
3909 4052 * Remove any trailing / from the mount point
3910 4053 */
3911 4054 (void) strlcpy(mntpt, root, sizeof (mntpt));
3912 4055 if (strcmp(root, "/") != 0) {
3913 4056 cp = mntpt + strlen(mntpt) - 1;
3914 4057 if (*cp == '/')
3915 4058 *cp = '\0';
3916 4059 }
3917 4060 found = 0;
3918 4061 while (getextmntent(fp, &mnt, sizeof (mnt)) == 0) {
3919 4062 if (strcmp(mnt.mnt_mountp, mntpt) == 0) {
3920 4063 found = 1;
3921 4064 break;
3922 4065 }
3923 4066 }
3924 4067
3925 4068 if (!found) {
3926 4069 if (bam_verbose)
3927 4070 bam_error(_("alternate root %s not in mnttab\n"),
3928 4071 mntpt);
3929 4072 (void) fclose(fp);
3930 4073 return (0);
3931 4074 }
3932 4075
3933 4076 if (strncmp(mnt.mnt_special, RAMDISK_SPECIAL,
3934 4077 strlen(RAMDISK_SPECIAL)) == 0) {
3935 4078 if (bam_verbose)
3936 4079 bam_error(_("%s is on a ramdisk device\n"), bam_root);
3937 4080 (void) fclose(fp);
3938 4081 return (1);
3939 4082 }
3940 4083
3941 4084 (void) fclose(fp);
3942 4085
3943 4086 return (0);
3944 4087 }
3945 4088
3946 4089 static int
3947 4090 is_boot_archive(char *root)
3948 4091 {
3949 4092 char path[PATH_MAX];
3950 4093 struct stat sb;
3951 4094 int error;
3952 4095 const char *fcn = "is_boot_archive()";
3953 4096
3954 4097 /*
3955 4098 * We can't create an archive without the create_ramdisk script
3956 4099 */
3957 4100 (void) snprintf(path, sizeof (path), "%s/%s", root, CREATE_RAMDISK);
3958 4101 error = stat(path, &sb);
3959 4102 INJECT_ERROR1("NOT_ARCHIVE_BASED", error = -1);
3960 4103 if (error == -1) {
3961 4104 if (bam_verbose)
3962 4105 bam_print(_("file not found: %s\n"), path);
3963 4106 BAM_DPRINTF(("%s: not a boot archive based Solaris "
3964 4107 "instance: %s\n", fcn, root));
3965 4108 return (0);
3966 4109 }
3967 4110
3968 4111 BAM_DPRINTF(("%s: *IS* a boot archive based Solaris instance: %s\n",
3969 4112 fcn, root));
3970 4113 return (1);
3971 4114 }
3972 4115
3973 4116 /*
3974 4117 * Need to call this for anything that operates on the GRUB menu
3975 4118 * In the x86 live upgrade case the directory /boot/grub may be present
3976 4119 * even on pre-newboot BEs. The authoritative way to check for a GRUB target
3977 4120 * is to check for the presence of the stage2 binary which is present
3978 4121 * only on GRUB targets (even on x86 boot partitions). Checking for the
3979 4122 * presence of the multiboot binary is not correct as it is not present
3980 4123 * on x86 boot partitions.
3981 4124 */
3982 4125 int
3983 4126 is_grub(const char *root)
3984 4127 {
3985 4128 char path[PATH_MAX];
3986 4129 struct stat sb;
3987 4130 void *defp;
3988 4131 boolean_t grub = B_FALSE;
3989 4132 const char *res = NULL;
3990 4133 const char *fcn = "is_grub()";
3991 4134
3992 4135 /* grub is disabled by default */
3993 4136 if ((defp = defopen_r(BE_DEFAULTS)) == NULL) {
3994 4137 return (0);
3995 4138 } else {
3996 4139 res = defread_r(BE_DFLT_BE_HAS_GRUB, defp);
3997 4140 if (res != NULL && res[0] != '\0') {
3998 4141 if (strcasecmp(res, "true") == 0)
3999 4142 grub = B_TRUE;
4000 4143 }
4001 4144 defclose_r(defp);
4002 4145 }
4003 4146
4004 4147 if (grub == B_TRUE) {
4005 4148 (void) snprintf(path, sizeof (path), "%s%s", root, GRUB_STAGE2);
4006 4149 if (stat(path, &sb) == -1) {
4007 4150 BAM_DPRINTF(("%s: Missing GRUB directory: %s\n",
4008 4151 fcn, path));
4009 4152 return (0);
4010 4153 } else
4011 4154 return (1);
4012 4155 }
4013 4156
4014 4157 return (0);
4015 4158 }
4016 4159
4017 4160 int
4018 4161 is_zfs(char *root)
4019 4162 {
4020 4163 struct statvfs vfs;
4021 4164 int ret;
4022 4165 const char *fcn = "is_zfs()";
4023 4166
4024 4167 ret = statvfs(root, &vfs);
4025 4168 INJECT_ERROR1("STATVFS_ZFS", ret = 1);
4026 4169 if (ret != 0) {
4027 4170 bam_error(_("statvfs failed for %s: %s\n"), root,
4028 4171 strerror(errno));
4029 4172 return (0);
4030 4173 }
4031 4174
4032 4175 if (strncmp(vfs.f_basetype, "zfs", strlen("zfs")) == 0) {
4033 4176 BAM_DPRINTF(("%s: is a ZFS filesystem: %s\n", fcn, root));
4034 4177 return (1);
4035 4178 } else {
4036 4179 BAM_DPRINTF(("%s: is *NOT* a ZFS filesystem: %s\n", fcn, root));
4037 4180 return (0);
4038 4181 }
4039 4182 }
4040 4183
4041 4184 int
4042 4185 is_pcfs(char *root)
4043 4186 {
4044 4187 struct statvfs vfs;
4045 4188 int ret;
4046 4189 const char *fcn = "is_pcfs()";
4047 4190
4048 4191 ret = statvfs(root, &vfs);
4049 4192 INJECT_ERROR1("STATVFS_PCFS", ret = 1);
4050 4193 if (ret != 0) {
4051 4194 bam_error(_("statvfs failed for %s: %s\n"), root,
4052 4195 strerror(errno));
4053 4196 return (0);
4054 4197 }
4055 4198
4056 4199 if (strncmp(vfs.f_basetype, "pcfs", strlen("pcfs")) == 0) {
4057 4200 BAM_DPRINTF(("%s: is a PCFS filesystem: %s\n", fcn, root));
4058 4201 return (1);
4059 4202 } else {
4060 4203 BAM_DPRINTF(("%s: is *NOT* a PCFS filesystem: %s\n",
4061 4204 fcn, root));
4062 4205 return (0);
4063 4206 }
4064 4207 }
4065 4208
4066 4209 static int
4067 4210 is_readonly(char *root)
4068 4211 {
4069 4212 int fd;
4070 4213 int error;
4071 4214 char testfile[PATH_MAX];
4072 4215 const char *fcn = "is_readonly()";
4073 4216
4074 4217 /*
4075 4218 * Using statvfs() to check for a read-only filesystem is not
4076 4219 * reliable. The only way to reliably test is to attempt to
4077 4220 * create a file
4078 4221 */
4079 4222 (void) snprintf(testfile, sizeof (testfile), "%s/%s.%d",
4080 4223 root, BOOTADM_RDONLY_TEST, getpid());
4081 4224
4082 4225 (void) unlink(testfile);
4083 4226
4084 4227 errno = 0;
4085 4228 fd = open(testfile, O_RDWR|O_CREAT|O_EXCL, 0644);
4086 4229 error = errno;
4087 4230 INJECT_ERROR2("RDONLY_TEST_ERROR", fd = -1, error = EACCES);
4088 4231 if (fd == -1 && error == EROFS) {
4089 4232 BAM_DPRINTF(("%s: is a READONLY filesystem: %s\n", fcn, root));
4090 4233 return (1);
4091 4234 } else if (fd == -1) {
4092 4235 bam_error(_("error during read-only test on %s: %s\n"),
4093 4236 root, strerror(error));
4094 4237 }
4095 4238
4096 4239 (void) close(fd);
4097 4240 (void) unlink(testfile);
4098 4241
4099 4242 BAM_DPRINTF(("%s: is a RDWR filesystem: %s\n", fcn, root));
4100 4243 return (0);
4101 4244 }
4102 4245
4103 4246 static error_t
4104 4247 update_archive(char *root, char *opt)
4105 4248 {
4106 4249 error_t ret;
4107 4250
4108 4251 assert(root);
4109 4252 assert(opt == NULL);
4110 4253
4111 4254 init_walk_args();
4112 4255 (void) umask(022);
4113 4256
4114 4257 /*
4115 4258 * Never update non-BE root in update_all
4116 4259 */
4117 4260 if (bam_update_all && !is_be(root))
4118 4261 return (BAM_SUCCESS);
4119 4262 /*
4120 4263 * root must belong to a boot archive based OS,
4121 4264 */
4122 4265 if (!is_boot_archive(root)) {
4123 4266 /*
4124 4267 * Emit message only if not in context of update_all.
4125 4268 * If in update_all, emit only if verbose flag is set.
4126 4269 */
4127 4270 if (!bam_update_all || bam_verbose)
4128 4271 bam_print(_("%s: not a boot archive based Solaris "
4129 4272 "instance\n"), root);
4130 4273 return (BAM_ERROR);
4131 4274 }
4132 4275
4133 4276 /*
4134 4277 * If smf check is requested when / is writable (can happen
4135 4278 * on first reboot following an upgrade because service
4136 4279 * dependency is messed up), skip the check.
4137 4280 */
4138 4281 if (bam_smf_check && !bam_root_readonly && !is_zfs(root))
4139 4282 return (BAM_SUCCESS);
4140 4283
4141 4284 /*
4142 4285 * Don't generate archive on ramdisk.
4143 4286 */
4144 4287 if (is_ramdisk(root))
4145 4288 return (BAM_SUCCESS);
4146 4289
4147 4290 /*
↓ open down ↓ |
343 lines elided |
↑ open up ↑ |
4148 4291 * root must be writable. This check applies to alternate
4149 4292 * root (-R option); bam_root_readonly applies to '/' only.
4150 4293 * The behaviour translates into being the one of a 'check'.
4151 4294 */
4152 4295 if (!bam_smf_check && !bam_check && is_readonly(root)) {
4153 4296 set_flag(RDONLY_FSCHK);
4154 4297 bam_check = 1;
4155 4298 }
4156 4299
4157 4300 /*
4301 + * Process the /etc/system.d/.self-assembly file.
4302 + */
4303 + if (build_etc_system_dir(bam_root) == BAM_ERROR)
4304 + return (BAM_ERROR);
4305 +
4306 + /*
4158 4307 * Now check if an update is really needed.
4159 4308 */
4160 4309 ret = update_required(root);
4161 4310
4162 4311 /*
4163 4312 * The check command (-n) is *not* a dry run.
4164 4313 * It only checks if the archive is in sync.
4165 4314 * A readonly filesystem has to be considered an error only if an update
4166 4315 * is required.
4167 4316 */
4168 4317 if (bam_nowrite()) {
4169 4318 if (is_flag_on(RDONLY_FSCHK)) {
4170 4319 bam_check = bam_saved_check;
4171 4320 if (ret > 0)
4172 4321 bam_error(_("%s filesystem is read-only, "
4173 4322 "skipping archives update\n"), root);
4174 4323 if (bam_update_all)
4175 4324 return ((ret != 0) ? BAM_ERROR : BAM_SUCCESS);
4176 4325 }
4177 4326
4178 4327 bam_exit((ret != 0) ? 1 : 0);
4179 4328 }
4180 4329
4181 4330 if (ret == 1) {
4182 4331 /* create the ramdisk */
4183 4332 ret = create_ramdisk(root);
4184 4333 }
4185 4334
4186 4335 /*
4187 4336 * if the archive is updated, save the new stat data and update the
4188 4337 * timestamp file
4189 4338 */
4190 4339 if (ret == 0 && walk_arg.new_nvlp != NULL) {
4191 4340 savenew(root);
4192 4341 update_timestamp(root);
4193 4342 }
4194 4343
4195 4344 clear_walk_args();
4196 4345
4197 4346 return (ret);
4198 4347 }
4199 4348
4200 4349 static char *
4201 4350 find_root_pool()
4202 4351 {
4203 4352 char *special = get_special("/");
4204 4353 char *p;
4205 4354
4206 4355 if (special == NULL)
4207 4356 return (NULL);
4208 4357
4209 4358 if (*special == '/') {
4210 4359 free(special);
4211 4360 return (NULL);
4212 4361 }
4213 4362
4214 4363 if ((p = strchr(special, '/')) != NULL)
4215 4364 *p = '\0';
4216 4365
4217 4366 return (special);
4218 4367 }
4219 4368
4220 4369 static error_t
4221 4370 synchronize_BE_menu(void)
4222 4371 {
4223 4372 struct stat sb;
4224 4373 char cmdline[PATH_MAX];
4225 4374 char cksum_line[PATH_MAX];
4226 4375 filelist_t flist = {0};
4227 4376 char *old_cksum_str;
4228 4377 char *old_size_str;
4229 4378 char *old_file;
4230 4379 char *curr_cksum_str;
4231 4380 char *curr_size_str;
4232 4381 char *curr_file;
4233 4382 char *pool = NULL;
4234 4383 char *mntpt = NULL;
4235 4384 zfs_mnted_t mnted;
4236 4385 FILE *cfp;
4237 4386 int found;
4238 4387 int ret;
4239 4388 const char *fcn = "synchronize_BE_menu()";
4240 4389
4241 4390 BAM_DPRINTF(("%s: entered. No args\n", fcn));
4242 4391
4243 4392 /* Check if findroot enabled LU BE */
4244 4393 if (stat(FINDROOT_INSTALLGRUB, &sb) != 0) {
4245 4394 BAM_DPRINTF(("%s: not a Live Upgrade BE\n", fcn));
4246 4395 return (BAM_SUCCESS);
4247 4396 }
4248 4397
4249 4398 if (stat(LU_MENU_CKSUM, &sb) != 0) {
4250 4399 BAM_DPRINTF(("%s: checksum file absent: %s\n",
4251 4400 fcn, LU_MENU_CKSUM));
4252 4401 goto menu_sync;
4253 4402 }
4254 4403
4255 4404 cfp = fopen(LU_MENU_CKSUM, "r");
4256 4405 INJECT_ERROR1("CKSUM_FILE_MISSING", cfp = NULL);
4257 4406 if (cfp == NULL) {
4258 4407 bam_error(_("failed to read GRUB menu checksum file: %s\n"),
4259 4408 LU_MENU_CKSUM);
4260 4409 goto menu_sync;
4261 4410 }
4262 4411 BAM_DPRINTF(("%s: opened checksum file: %s\n", fcn, LU_MENU_CKSUM));
4263 4412
4264 4413 found = 0;
4265 4414 while (s_fgets(cksum_line, sizeof (cksum_line), cfp) != NULL) {
4266 4415 INJECT_ERROR1("MULTIPLE_CKSUM", found = 1);
4267 4416 if (found) {
4268 4417 bam_error(_("multiple checksums for GRUB menu in "
4269 4418 "checksum file: %s\n"), LU_MENU_CKSUM);
4270 4419 (void) fclose(cfp);
4271 4420 goto menu_sync;
4272 4421 }
4273 4422 found = 1;
4274 4423 }
4275 4424 BAM_DPRINTF(("%s: read checksum file: %s\n", fcn, LU_MENU_CKSUM));
4276 4425
4277 4426
4278 4427 old_cksum_str = strtok(cksum_line, " \t");
4279 4428 old_size_str = strtok(NULL, " \t");
4280 4429 old_file = strtok(NULL, " \t");
4281 4430
4282 4431 INJECT_ERROR1("OLD_CKSUM_NULL", old_cksum_str = NULL);
4283 4432 INJECT_ERROR1("OLD_SIZE_NULL", old_size_str = NULL);
4284 4433 INJECT_ERROR1("OLD_FILE_NULL", old_file = NULL);
4285 4434 if (old_cksum_str == NULL || old_size_str == NULL || old_file == NULL) {
4286 4435 bam_error(_("error parsing GRUB menu checksum file: %s\n"),
4287 4436 LU_MENU_CKSUM);
4288 4437 goto menu_sync;
4289 4438 }
4290 4439 BAM_DPRINTF(("%s: parsed checksum file: %s\n", fcn, LU_MENU_CKSUM));
4291 4440
4292 4441 /* Get checksum of current menu */
4293 4442 pool = find_root_pool();
4294 4443 if (pool) {
4295 4444 mntpt = mount_top_dataset(pool, &mnted);
4296 4445 if (mntpt == NULL) {
4297 4446 bam_error(_("failed to mount top dataset for %s\n"),
4298 4447 pool);
4299 4448 free(pool);
4300 4449 return (BAM_ERROR);
4301 4450 }
4302 4451 (void) snprintf(cmdline, sizeof (cmdline), "%s %s%s",
4303 4452 CKSUM, mntpt, GRUB_MENU);
4304 4453 } else {
4305 4454 (void) snprintf(cmdline, sizeof (cmdline), "%s %s",
4306 4455 CKSUM, GRUB_MENU);
4307 4456 }
4308 4457 ret = exec_cmd(cmdline, &flist);
4309 4458 if (pool) {
4310 4459 (void) umount_top_dataset(pool, mnted, mntpt);
4311 4460 free(pool);
4312 4461 }
4313 4462 INJECT_ERROR1("GET_CURR_CKSUM", ret = 1);
4314 4463 if (ret != 0) {
4315 4464 bam_error(_("error generating checksum of GRUB menu\n"));
4316 4465 return (BAM_ERROR);
4317 4466 }
4318 4467 BAM_DPRINTF(("%s: successfully generated checksum\n", fcn));
4319 4468
4320 4469 INJECT_ERROR1("GET_CURR_CKSUM_OUTPUT", flist.head = NULL);
4321 4470 if ((flist.head == NULL) || (flist.head != flist.tail)) {
4322 4471 bam_error(_("bad checksum generated for GRUB menu\n"));
4323 4472 filelist_free(&flist);
4324 4473 return (BAM_ERROR);
4325 4474 }
4326 4475 BAM_DPRINTF(("%s: generated checksum output valid\n", fcn));
4327 4476
4328 4477 curr_cksum_str = strtok(flist.head->line, " \t");
4329 4478 curr_size_str = strtok(NULL, " \t");
4330 4479 curr_file = strtok(NULL, " \t");
4331 4480
4332 4481 INJECT_ERROR1("CURR_CKSUM_NULL", curr_cksum_str = NULL);
4333 4482 INJECT_ERROR1("CURR_SIZE_NULL", curr_size_str = NULL);
4334 4483 INJECT_ERROR1("CURR_FILE_NULL", curr_file = NULL);
4335 4484 if (curr_cksum_str == NULL || curr_size_str == NULL ||
4336 4485 curr_file == NULL) {
4337 4486 bam_error(_("error parsing checksum generated "
4338 4487 "for GRUB menu\n"));
4339 4488 filelist_free(&flist);
4340 4489 return (BAM_ERROR);
4341 4490 }
4342 4491 BAM_DPRINTF(("%s: successfully parsed generated checksum\n", fcn));
4343 4492
4344 4493 if (strcmp(old_cksum_str, curr_cksum_str) == 0 &&
4345 4494 strcmp(old_size_str, curr_size_str) == 0 &&
4346 4495 strcmp(old_file, curr_file) == 0) {
4347 4496 filelist_free(&flist);
4348 4497 BAM_DPRINTF(("%s: no change in checksum of GRUB menu\n", fcn));
4349 4498 return (BAM_SUCCESS);
4350 4499 }
4351 4500
4352 4501 filelist_free(&flist);
4353 4502
4354 4503 /* cksum doesn't match - the menu has changed */
4355 4504 BAM_DPRINTF(("%s: checksum of GRUB menu has changed\n", fcn));
4356 4505
4357 4506 menu_sync:
4358 4507 bam_print(_("propagating updated GRUB menu\n"));
4359 4508
4360 4509 (void) snprintf(cmdline, sizeof (cmdline),
4361 4510 "/bin/sh -c '. %s > /dev/null; %s %s yes > /dev/null'",
4362 4511 LULIB, LULIB_PROPAGATE_FILE, GRUB_MENU);
4363 4512 ret = exec_cmd(cmdline, NULL);
4364 4513 INJECT_ERROR1("PROPAGATE_MENU", ret = 1);
4365 4514 if (ret != 0) {
4366 4515 bam_error(_("error propagating updated GRUB menu\n"));
4367 4516 return (BAM_ERROR);
4368 4517 }
4369 4518 BAM_DPRINTF(("%s: successfully propagated GRUB menu\n", fcn));
4370 4519
4371 4520 (void) snprintf(cmdline, sizeof (cmdline), "/bin/cp %s %s > /dev/null",
4372 4521 GRUB_MENU, GRUB_BACKUP_MENU);
4373 4522 ret = exec_cmd(cmdline, NULL);
4374 4523 INJECT_ERROR1("CREATE_BACKUP", ret = 1);
4375 4524 if (ret != 0) {
4376 4525 bam_error(_("failed to create backup for GRUB menu: %s\n"),
4377 4526 GRUB_BACKUP_MENU);
4378 4527 return (BAM_ERROR);
4379 4528 }
4380 4529 BAM_DPRINTF(("%s: successfully created backup GRUB menu: %s\n",
4381 4530 fcn, GRUB_BACKUP_MENU));
4382 4531
4383 4532 (void) snprintf(cmdline, sizeof (cmdline),
4384 4533 "/bin/sh -c '. %s > /dev/null; %s %s no > /dev/null'",
4385 4534 LULIB, LULIB_PROPAGATE_FILE, GRUB_BACKUP_MENU);
4386 4535 ret = exec_cmd(cmdline, NULL);
4387 4536 INJECT_ERROR1("PROPAGATE_BACKUP", ret = 1);
4388 4537 if (ret != 0) {
4389 4538 bam_error(_("error propagating backup GRUB menu: %s\n"),
4390 4539 GRUB_BACKUP_MENU);
4391 4540 return (BAM_ERROR);
4392 4541 }
4393 4542 BAM_DPRINTF(("%s: successfully propagated backup GRUB menu: %s\n",
4394 4543 fcn, GRUB_BACKUP_MENU));
4395 4544
4396 4545 (void) snprintf(cmdline, sizeof (cmdline), "%s %s > %s",
4397 4546 CKSUM, GRUB_MENU, LU_MENU_CKSUM);
4398 4547 ret = exec_cmd(cmdline, NULL);
4399 4548 INJECT_ERROR1("CREATE_CKSUM_FILE", ret = 1);
4400 4549 if (ret != 0) {
4401 4550 bam_error(_("failed to write GRUB menu checksum file: %s\n"),
4402 4551 LU_MENU_CKSUM);
4403 4552 return (BAM_ERROR);
4404 4553 }
4405 4554 BAM_DPRINTF(("%s: successfully created checksum file: %s\n",
4406 4555 fcn, LU_MENU_CKSUM));
4407 4556
4408 4557 (void) snprintf(cmdline, sizeof (cmdline),
4409 4558 "/bin/sh -c '. %s > /dev/null; %s %s no > /dev/null'",
4410 4559 LULIB, LULIB_PROPAGATE_FILE, LU_MENU_CKSUM);
4411 4560 ret = exec_cmd(cmdline, NULL);
4412 4561 INJECT_ERROR1("PROPAGATE_MENU_CKSUM_FILE", ret = 1);
4413 4562 if (ret != 0) {
4414 4563 bam_error(_("error propagating GRUB menu checksum file: %s\n"),
4415 4564 LU_MENU_CKSUM);
4416 4565 return (BAM_ERROR);
4417 4566 }
4418 4567 BAM_DPRINTF(("%s: successfully propagated checksum file: %s\n",
4419 4568 fcn, LU_MENU_CKSUM));
4420 4569
4421 4570 return (BAM_SUCCESS);
4422 4571 }
4423 4572
4424 4573 static error_t
4425 4574 update_all(char *root, char *opt)
4426 4575 {
4427 4576 struct extmnttab mnt;
4428 4577 struct stat sb;
4429 4578 FILE *fp;
4430 4579 char multibt[PATH_MAX];
4431 4580 char creatram[PATH_MAX];
4432 4581 error_t ret = BAM_SUCCESS;
4433 4582
4434 4583 assert(root);
4435 4584 assert(opt == NULL);
4436 4585
4437 4586 if (bam_rootlen != 1 || *root != '/') {
4438 4587 elide_trailing_slash(root, multibt, sizeof (multibt));
4439 4588 bam_error(_("an alternate root (%s) cannot be used with this "
4440 4589 "sub-command\n"), multibt);
4441 4590 return (BAM_ERROR);
4442 4591 }
4443 4592
4444 4593 /*
4445 4594 * First update archive for current root
4446 4595 */
4447 4596 if (update_archive(root, opt) != BAM_SUCCESS)
4448 4597 ret = BAM_ERROR;
4449 4598
4450 4599 if (ret == BAM_ERROR)
4451 4600 goto out;
4452 4601
4453 4602 /*
4454 4603 * Now walk the mount table, performing archive update
4455 4604 * for all mounted Newboot root filesystems
4456 4605 */
4457 4606 fp = fopen(MNTTAB, "r");
4458 4607 if (fp == NULL) {
4459 4608 bam_error(_("failed to open file: %s: %s\n"),
4460 4609 MNTTAB, strerror(errno));
4461 4610 ret = BAM_ERROR;
4462 4611 goto out;
4463 4612 }
4464 4613
4465 4614 resetmnttab(fp);
4466 4615
4467 4616 while (getextmntent(fp, &mnt, sizeof (mnt)) == 0) {
4468 4617 if (mnt.mnt_special == NULL)
4469 4618 continue;
4470 4619 if ((strcmp(mnt.mnt_fstype, MNTTYPE_ZFS) != 0) &&
4471 4620 (strncmp(mnt.mnt_special, "/dev/", strlen("/dev/")) != 0))
4472 4621 continue;
4473 4622 if (strcmp(mnt.mnt_mountp, "/") == 0)
4474 4623 continue;
4475 4624
4476 4625 (void) snprintf(creatram, sizeof (creatram), "%s/%s",
4477 4626 mnt.mnt_mountp, CREATE_RAMDISK);
4478 4627
4479 4628 if (stat(creatram, &sb) == -1)
4480 4629 continue;
4481 4630
4482 4631 /*
4483 4632 * We put a trailing slash to be consistent with root = "/"
4484 4633 * case, such that we don't have to print // in some cases.
4485 4634 */
4486 4635 (void) snprintf(rootbuf, sizeof (rootbuf), "%s/",
4487 4636 mnt.mnt_mountp);
4488 4637 bam_rootlen = strlen(rootbuf);
4489 4638
4490 4639 /*
4491 4640 * It's possible that other mounts may be an alternate boot
4492 4641 * architecture, so check it again.
4493 4642 */
4494 4643 if ((get_boot_cap(rootbuf) != BAM_SUCCESS) ||
4495 4644 (update_archive(rootbuf, opt) != BAM_SUCCESS))
4496 4645 ret = BAM_ERROR;
4497 4646 }
4498 4647
4499 4648 (void) fclose(fp);
4500 4649
4501 4650 out:
4502 4651 /*
4503 4652 * We no longer use biosdev for Live Upgrade. Hence
4504 4653 * there is no need to defer (to shutdown time) any fdisk
4505 4654 * updates
4506 4655 */
4507 4656 if (stat(GRUB_fdisk, &sb) == 0 || stat(GRUB_fdisk_target, &sb) == 0) {
4508 4657 bam_error(_("Deferred FDISK update file(s) found: %s, %s. "
4509 4658 "Not supported.\n"), GRUB_fdisk, GRUB_fdisk_target);
4510 4659 }
4511 4660
4512 4661 /*
4513 4662 * If user has updated menu in current BE, propagate the
4514 4663 * updates to all BEs.
4515 4664 */
4516 4665 if (sync_menu && synchronize_BE_menu() != BAM_SUCCESS)
4517 4666 ret = BAM_ERROR;
4518 4667
4519 4668 return (ret);
4520 4669 }
4521 4670
4522 4671 static void
4523 4672 append_line(menu_t *mp, line_t *lp)
4524 4673 {
4525 4674 if (mp->start == NULL) {
4526 4675 mp->start = lp;
4527 4676 } else {
4528 4677 mp->end->next = lp;
4529 4678 lp->prev = mp->end;
4530 4679 }
4531 4680 mp->end = lp;
4532 4681 }
4533 4682
4534 4683 void
4535 4684 unlink_line(menu_t *mp, line_t *lp)
4536 4685 {
4537 4686 /* unlink from list */
4538 4687 if (lp->prev)
4539 4688 lp->prev->next = lp->next;
4540 4689 else
4541 4690 mp->start = lp->next;
4542 4691 if (lp->next)
4543 4692 lp->next->prev = lp->prev;
4544 4693 else
4545 4694 mp->end = lp->prev;
4546 4695 }
4547 4696
4548 4697 static entry_t *
4549 4698 boot_entry_new(menu_t *mp, line_t *start, line_t *end)
4550 4699 {
4551 4700 entry_t *ent, *prev;
4552 4701 const char *fcn = "boot_entry_new()";
4553 4702
4554 4703 assert(mp);
4555 4704 assert(start);
4556 4705 assert(end);
4557 4706
4558 4707 ent = s_calloc(1, sizeof (entry_t));
4559 4708 BAM_DPRINTF(("%s: new boot entry alloced\n", fcn));
4560 4709 ent->start = start;
4561 4710 ent->end = end;
4562 4711
4563 4712 if (mp->entries == NULL) {
4564 4713 mp->entries = ent;
4565 4714 BAM_DPRINTF(("%s: (first) new boot entry created\n", fcn));
4566 4715 return (ent);
4567 4716 }
4568 4717
4569 4718 prev = mp->entries;
4570 4719 while (prev->next)
4571 4720 prev = prev->next;
4572 4721 prev->next = ent;
4573 4722 ent->prev = prev;
4574 4723 BAM_DPRINTF(("%s: new boot entry linked in\n", fcn));
4575 4724 return (ent);
4576 4725 }
4577 4726
4578 4727 static void
4579 4728 boot_entry_addline(entry_t *ent, line_t *lp)
4580 4729 {
4581 4730 if (ent)
4582 4731 ent->end = lp;
4583 4732 }
4584 4733
4585 4734 /*
4586 4735 * Check whether cmd matches the one indexed by which, and whether arg matches
4587 4736 * str. which must be either KERNEL_CMD or MODULE_CMD, and a match to the
4588 4737 * respective *_DOLLAR_CMD is also acceptable. The arg is searched using
4589 4738 * strstr(), so it can be a partial match.
4590 4739 */
4591 4740 static int
4592 4741 check_cmd(const char *cmd, const int which, const char *arg, const char *str)
4593 4742 {
4594 4743 int ret;
4595 4744 const char *fcn = "check_cmd()";
4596 4745
4597 4746 BAM_DPRINTF(("%s: entered. args: %s %s\n", fcn, arg, str));
4598 4747
4599 4748 if (cmd != NULL) {
4600 4749 if ((strcmp(cmd, menu_cmds[which]) != 0) &&
4601 4750 (strcmp(cmd, menu_cmds[which + 1]) != 0)) {
4602 4751 BAM_DPRINTF(("%s: command %s does not match %s\n",
4603 4752 fcn, cmd, menu_cmds[which]));
4604 4753 return (0);
4605 4754 }
4606 4755 ret = (strstr(arg, str) != NULL);
4607 4756 } else
4608 4757 ret = 0;
4609 4758
4610 4759 if (ret) {
4611 4760 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
4612 4761 } else {
4613 4762 BAM_DPRINTF(("%s: returning FAILURE\n", fcn));
4614 4763 }
4615 4764
4616 4765 return (ret);
4617 4766 }
4618 4767
4619 4768 static error_t
4620 4769 kernel_parser(entry_t *entry, char *cmd, char *arg, int linenum)
4621 4770 {
4622 4771 const char *fcn = "kernel_parser()";
4623 4772
4624 4773 assert(entry);
4625 4774 assert(cmd);
4626 4775 assert(arg);
4627 4776
4628 4777 if (strcmp(cmd, menu_cmds[KERNEL_CMD]) != 0 &&
4629 4778 strcmp(cmd, menu_cmds[KERNEL_DOLLAR_CMD]) != 0) {
4630 4779 BAM_DPRINTF(("%s: not a kernel command: %s\n", fcn, cmd));
4631 4780 return (BAM_ERROR);
4632 4781 }
4633 4782
4634 4783 if (strncmp(arg, DIRECT_BOOT_32, sizeof (DIRECT_BOOT_32) - 1) == 0) {
4635 4784 BAM_DPRINTF(("%s: setting DBOOT|DBOOT_32 flag: %s\n",
4636 4785 fcn, arg));
4637 4786 entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_32BIT;
4638 4787 } else if (strncmp(arg, DIRECT_BOOT_KERNEL,
4639 4788 sizeof (DIRECT_BOOT_KERNEL) - 1) == 0) {
4640 4789 BAM_DPRINTF(("%s: setting DBOOT flag: %s\n", fcn, arg));
4641 4790 entry->flags |= BAM_ENTRY_DBOOT;
4642 4791 } else if (strncmp(arg, DIRECT_BOOT_64,
4643 4792 sizeof (DIRECT_BOOT_64) - 1) == 0) {
4644 4793 BAM_DPRINTF(("%s: setting DBOOT|DBOOT_64 flag: %s\n",
4645 4794 fcn, arg));
4646 4795 entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_64BIT;
4647 4796 } else if (strncmp(arg, DIRECT_BOOT_FAILSAFE_KERNEL,
4648 4797 sizeof (DIRECT_BOOT_FAILSAFE_KERNEL) - 1) == 0) {
4649 4798 BAM_DPRINTF(("%s: setting DBOOT|DBOOT_FAILSAFE flag: %s\n",
4650 4799 fcn, arg));
4651 4800 entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_FAILSAFE;
4652 4801 } else if (strncmp(arg, DIRECT_BOOT_FAILSAFE_32,
4653 4802 sizeof (DIRECT_BOOT_FAILSAFE_32) - 1) == 0) {
4654 4803 BAM_DPRINTF(("%s: setting DBOOT|DBOOT_FAILSAFE|DBOOT_32 "
4655 4804 "flag: %s\n", fcn, arg));
4656 4805 entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_FAILSAFE
4657 4806 | BAM_ENTRY_32BIT;
4658 4807 } else if (strncmp(arg, DIRECT_BOOT_FAILSAFE_64,
4659 4808 sizeof (DIRECT_BOOT_FAILSAFE_64) - 1) == 0) {
4660 4809 BAM_DPRINTF(("%s: setting DBOOT|DBOOT_FAILSAFE|DBOOT_64 "
4661 4810 "flag: %s\n", fcn, arg));
4662 4811 entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_FAILSAFE
4663 4812 | BAM_ENTRY_64BIT;
4664 4813 } else if (strncmp(arg, MULTI_BOOT, sizeof (MULTI_BOOT) - 1) == 0) {
4665 4814 BAM_DPRINTF(("%s: setting MULTIBOOT flag: %s\n", fcn, arg));
4666 4815 entry->flags |= BAM_ENTRY_MULTIBOOT;
4667 4816 } else if (strncmp(arg, MULTI_BOOT_FAILSAFE,
4668 4817 sizeof (MULTI_BOOT_FAILSAFE) - 1) == 0) {
4669 4818 BAM_DPRINTF(("%s: setting MULTIBOOT|MULTIBOOT_FAILSAFE "
4670 4819 "flag: %s\n", fcn, arg));
4671 4820 entry->flags |= BAM_ENTRY_MULTIBOOT | BAM_ENTRY_FAILSAFE;
4672 4821 } else if (strstr(arg, XEN_KERNEL_SUBSTR)) {
4673 4822 BAM_DPRINTF(("%s: setting XEN HV flag: %s\n", fcn, arg));
4674 4823 entry->flags |= BAM_ENTRY_HV;
4675 4824 } else if (!(entry->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU))) {
4676 4825 BAM_DPRINTF(("%s: is HAND kernel flag: %s\n", fcn, arg));
4677 4826 return (BAM_ERROR);
4678 4827 } else if (strncmp(arg, KERNEL_PREFIX, strlen(KERNEL_PREFIX)) == 0 &&
4679 4828 strstr(arg, UNIX_SPACE)) {
4680 4829 entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_32BIT;
4681 4830 } else if (strncmp(arg, KERNEL_PREFIX, strlen(KERNEL_PREFIX)) == 0 &&
4682 4831 strstr(arg, AMD_UNIX_SPACE)) {
4683 4832 entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_64BIT;
4684 4833 } else {
4685 4834 BAM_DPRINTF(("%s: is UNKNOWN kernel entry: %s\n", fcn, arg));
4686 4835 bam_error(_("kernel command on line %d not recognized.\n"),
4687 4836 linenum);
4688 4837 return (BAM_ERROR);
4689 4838 }
4690 4839
4691 4840 return (BAM_SUCCESS);
4692 4841 }
4693 4842
4694 4843 static error_t
4695 4844 module_parser(entry_t *entry, char *cmd, char *arg, int linenum)
4696 4845 {
4697 4846 const char *fcn = "module_parser()";
4698 4847
4699 4848 assert(entry);
4700 4849 assert(cmd);
4701 4850 assert(arg);
4702 4851
4703 4852 if (strcmp(cmd, menu_cmds[MODULE_CMD]) != 0 &&
4704 4853 strcmp(cmd, menu_cmds[MODULE_DOLLAR_CMD]) != 0) {
4705 4854 BAM_DPRINTF(("%s: not module cmd: %s\n", fcn, cmd));
4706 4855 return (BAM_ERROR);
4707 4856 }
4708 4857
4709 4858 if (strcmp(arg, DIRECT_BOOT_ARCHIVE) == 0 ||
4710 4859 strcmp(arg, DIRECT_BOOT_ARCHIVE_32) == 0 ||
4711 4860 strcmp(arg, DIRECT_BOOT_ARCHIVE_64) == 0 ||
4712 4861 strcmp(arg, MULTIBOOT_ARCHIVE) == 0 ||
4713 4862 strcmp(arg, FAILSAFE_ARCHIVE) == 0 ||
4714 4863 strcmp(arg, FAILSAFE_ARCHIVE_32) == 0 ||
4715 4864 strcmp(arg, FAILSAFE_ARCHIVE_64) == 0 ||
4716 4865 strcmp(arg, XEN_KERNEL_MODULE_LINE) == 0 ||
4717 4866 strcmp(arg, XEN_KERNEL_MODULE_LINE_ZFS) == 0) {
4718 4867 BAM_DPRINTF(("%s: bootadm or LU module cmd: %s\n", fcn, arg));
4719 4868 return (BAM_SUCCESS);
4720 4869 } else if (!(entry->flags & BAM_ENTRY_BOOTADM) &&
4721 4870 !(entry->flags & BAM_ENTRY_LU)) {
4722 4871 /* don't emit warning for hand entries */
4723 4872 BAM_DPRINTF(("%s: is HAND module: %s\n", fcn, arg));
4724 4873 return (BAM_ERROR);
4725 4874 } else {
4726 4875 BAM_DPRINTF(("%s: is UNKNOWN module: %s\n", fcn, arg));
4727 4876 bam_error(_("module command on line %d not recognized.\n"),
4728 4877 linenum);
4729 4878 return (BAM_ERROR);
4730 4879 }
4731 4880 }
4732 4881
4733 4882 /*
4734 4883 * A line in menu.lst looks like
4735 4884 * [ ]*<cmd>[ \t=]*<arg>*
4736 4885 */
4737 4886 static void
4738 4887 line_parser(menu_t *mp, char *str, int *lineNum, int *entryNum)
4739 4888 {
4740 4889 /*
4741 4890 * save state across calls. This is so that
4742 4891 * header gets the right entry# after title has
4743 4892 * been processed
4744 4893 */
4745 4894 static line_t *prev = NULL;
4746 4895 static entry_t *curr_ent = NULL;
4747 4896 static int in_liveupgrade = 0;
4748 4897 static int is_libbe_ent = 0;
4749 4898
4750 4899 line_t *lp;
4751 4900 char *cmd, *sep, *arg;
4752 4901 char save, *cp, *line;
4753 4902 menu_flag_t flag = BAM_INVALID;
4754 4903 const char *fcn = "line_parser()";
4755 4904
4756 4905 cmd = NULL;
4757 4906 if (str == NULL) {
4758 4907 return;
4759 4908 }
4760 4909
4761 4910 /*
4762 4911 * First save a copy of the entire line.
4763 4912 * We use this later to set the line field.
4764 4913 */
4765 4914 line = s_strdup(str);
4766 4915
4767 4916 /* Eat up leading whitespace */
4768 4917 while (*str == ' ' || *str == '\t')
4769 4918 str++;
4770 4919
4771 4920 if (*str == '#') { /* comment */
4772 4921 cmd = s_strdup("#");
4773 4922 sep = NULL;
4774 4923 arg = s_strdup(str + 1);
4775 4924 flag = BAM_COMMENT;
4776 4925 if (strstr(arg, BAM_LU_HDR) != NULL) {
4777 4926 in_liveupgrade = 1;
4778 4927 } else if (strstr(arg, BAM_LU_FTR) != NULL) {
4779 4928 in_liveupgrade = 0;
4780 4929 } else if (strstr(arg, BAM_LIBBE_FTR) != NULL) {
4781 4930 is_libbe_ent = 1;
4782 4931 }
4783 4932 } else if (*str == '\0') { /* blank line */
4784 4933 cmd = sep = arg = NULL;
4785 4934 flag = BAM_EMPTY;
4786 4935 } else {
4787 4936 /*
4788 4937 * '=' is not a documented separator in grub syntax.
4789 4938 * However various development bits use '=' as a
4790 4939 * separator. In addition, external users also
4791 4940 * use = as a separator. So we will allow that usage.
4792 4941 */
4793 4942 cp = str;
4794 4943 while (*str != ' ' && *str != '\t' && *str != '=') {
4795 4944 if (*str == '\0') {
4796 4945 cmd = s_strdup(cp);
4797 4946 sep = arg = NULL;
4798 4947 break;
4799 4948 }
4800 4949 str++;
4801 4950 }
4802 4951
4803 4952 if (*str != '\0') {
4804 4953 save = *str;
4805 4954 *str = '\0';
4806 4955 cmd = s_strdup(cp);
4807 4956 *str = save;
4808 4957
4809 4958 str++;
4810 4959 save = *str;
4811 4960 *str = '\0';
4812 4961 sep = s_strdup(str - 1);
4813 4962 *str = save;
4814 4963
4815 4964 while (*str == ' ' || *str == '\t')
4816 4965 str++;
4817 4966 if (*str == '\0')
4818 4967 arg = NULL;
4819 4968 else
4820 4969 arg = s_strdup(str);
4821 4970 }
4822 4971 }
4823 4972
4824 4973 lp = s_calloc(1, sizeof (line_t));
4825 4974
4826 4975 lp->cmd = cmd;
4827 4976 lp->sep = sep;
4828 4977 lp->arg = arg;
4829 4978 lp->line = line;
4830 4979 lp->lineNum = ++(*lineNum);
4831 4980 if (cmd && strcmp(cmd, menu_cmds[TITLE_CMD]) == 0) {
4832 4981 lp->entryNum = ++(*entryNum);
4833 4982 lp->flags = BAM_TITLE;
4834 4983 if (prev && prev->flags == BAM_COMMENT &&
4835 4984 prev->arg && strcmp(prev->arg, BAM_BOOTADM_HDR) == 0) {
4836 4985 prev->entryNum = lp->entryNum;
4837 4986 curr_ent = boot_entry_new(mp, prev, lp);
4838 4987 curr_ent->flags |= BAM_ENTRY_BOOTADM;
4839 4988 BAM_DPRINTF(("%s: is bootadm(1M) entry: %s\n",
4840 4989 fcn, arg));
4841 4990 } else {
4842 4991 curr_ent = boot_entry_new(mp, lp, lp);
4843 4992 if (in_liveupgrade) {
4844 4993 curr_ent->flags |= BAM_ENTRY_LU;
4845 4994 BAM_DPRINTF(("%s: is LU entry: %s\n",
4846 4995 fcn, arg));
4847 4996 }
4848 4997 }
4849 4998 curr_ent->entryNum = *entryNum;
4850 4999 } else if (flag != BAM_INVALID) {
4851 5000 /*
4852 5001 * For header comments, the entry# is "fixed up"
4853 5002 * by the subsequent title
4854 5003 */
4855 5004 lp->entryNum = *entryNum;
4856 5005 lp->flags = flag;
4857 5006 } else {
4858 5007 lp->entryNum = *entryNum;
4859 5008
4860 5009 if (*entryNum == ENTRY_INIT) {
4861 5010 lp->flags = BAM_GLOBAL;
4862 5011 } else {
4863 5012 lp->flags = BAM_ENTRY;
4864 5013
4865 5014 if (cmd && arg) {
4866 5015 if (strcmp(cmd, menu_cmds[ROOT_CMD]) == 0) {
4867 5016 BAM_DPRINTF(("%s: setting ROOT: %s\n",
4868 5017 fcn, arg));
4869 5018 curr_ent->flags |= BAM_ENTRY_ROOT;
4870 5019 } else if (strcmp(cmd, menu_cmds[FINDROOT_CMD])
4871 5020 == 0) {
4872 5021 BAM_DPRINTF(("%s: setting "
4873 5022 "FINDROOT: %s\n", fcn, arg));
4874 5023 curr_ent->flags |= BAM_ENTRY_FINDROOT;
4875 5024 } else if (strcmp(cmd,
4876 5025 menu_cmds[CHAINLOADER_CMD]) == 0) {
4877 5026 BAM_DPRINTF(("%s: setting "
4878 5027 "CHAINLOADER: %s\n", fcn, arg));
4879 5028 curr_ent->flags |=
4880 5029 BAM_ENTRY_CHAINLOADER;
4881 5030 } else if (kernel_parser(curr_ent, cmd, arg,
4882 5031 lp->lineNum) != BAM_SUCCESS) {
4883 5032 (void) module_parser(curr_ent, cmd,
4884 5033 arg, lp->lineNum);
4885 5034 }
4886 5035 }
4887 5036 }
4888 5037 }
4889 5038
4890 5039 /* record default, old default, and entry line ranges */
4891 5040 if (lp->flags == BAM_GLOBAL && lp->cmd != NULL &&
4892 5041 strcmp(lp->cmd, menu_cmds[DEFAULT_CMD]) == 0) {
4893 5042 mp->curdefault = lp;
4894 5043 } else if (lp->flags == BAM_COMMENT &&
4895 5044 strncmp(lp->arg, BAM_OLDDEF, strlen(BAM_OLDDEF)) == 0) {
4896 5045 mp->olddefault = lp;
4897 5046 } else if (lp->flags == BAM_COMMENT &&
4898 5047 strncmp(lp->arg, BAM_OLD_RC_DEF, strlen(BAM_OLD_RC_DEF)) == 0) {
4899 5048 mp->old_rc_default = lp;
4900 5049 } else if (lp->flags == BAM_ENTRY ||
4901 5050 (lp->flags == BAM_COMMENT &&
4902 5051 ((strcmp(lp->arg, BAM_BOOTADM_FTR) == 0) || is_libbe_ent))) {
4903 5052 if (is_libbe_ent) {
4904 5053 curr_ent->flags |= BAM_ENTRY_LIBBE;
4905 5054 is_libbe_ent = 0;
4906 5055 }
4907 5056
4908 5057 boot_entry_addline(curr_ent, lp);
4909 5058 }
4910 5059 append_line(mp, lp);
4911 5060
4912 5061 prev = lp;
4913 5062 }
4914 5063
4915 5064 void
4916 5065 update_numbering(menu_t *mp)
4917 5066 {
4918 5067 int lineNum;
4919 5068 int entryNum;
4920 5069 int old_default_value;
4921 5070 line_t *lp, *prev, *default_lp, *default_entry;
4922 5071 char buf[PATH_MAX];
4923 5072
4924 5073 if (mp->start == NULL) {
4925 5074 return;
4926 5075 }
4927 5076
4928 5077 lineNum = LINE_INIT;
4929 5078 entryNum = ENTRY_INIT;
4930 5079 old_default_value = ENTRY_INIT;
4931 5080 lp = default_lp = default_entry = NULL;
4932 5081
4933 5082 prev = NULL;
4934 5083 for (lp = mp->start; lp; prev = lp, lp = lp->next) {
4935 5084 lp->lineNum = ++lineNum;
4936 5085
4937 5086 /*
4938 5087 * Get the value of the default command
4939 5088 */
4940 5089 if (lp->entryNum == ENTRY_INIT && lp->cmd != NULL &&
4941 5090 strcmp(lp->cmd, menu_cmds[DEFAULT_CMD]) == 0 &&
4942 5091 lp->arg) {
4943 5092 old_default_value = atoi(lp->arg);
4944 5093 default_lp = lp;
4945 5094 }
4946 5095
4947 5096 /*
4948 5097 * If not a booting entry, nothing else to fix for this
4949 5098 * entry
4950 5099 */
4951 5100 if (lp->entryNum == ENTRY_INIT)
4952 5101 continue;
4953 5102
4954 5103 /*
4955 5104 * Record the position of the default entry.
4956 5105 * The following works because global
4957 5106 * commands like default and timeout should precede
4958 5107 * actual boot entries, so old_default_value
4959 5108 * is already known (or default cmd is missing).
4960 5109 */
4961 5110 if (default_entry == NULL &&
4962 5111 old_default_value != ENTRY_INIT &&
4963 5112 lp->entryNum == old_default_value) {
4964 5113 default_entry = lp;
4965 5114 }
4966 5115
4967 5116 /*
4968 5117 * Now fixup the entry number
4969 5118 */
4970 5119 if (lp->cmd != NULL &&
4971 5120 strcmp(lp->cmd, menu_cmds[TITLE_CMD]) == 0) {
4972 5121 lp->entryNum = ++entryNum;
4973 5122 /* fixup the bootadm header */
4974 5123 if (prev && prev->flags == BAM_COMMENT &&
4975 5124 prev->arg &&
4976 5125 strcmp(prev->arg, BAM_BOOTADM_HDR) == 0) {
4977 5126 prev->entryNum = lp->entryNum;
4978 5127 }
4979 5128 } else {
4980 5129 lp->entryNum = entryNum;
4981 5130 }
4982 5131 }
4983 5132
4984 5133 /*
4985 5134 * No default command in menu, simply return
4986 5135 */
4987 5136 if (default_lp == NULL) {
4988 5137 return;
4989 5138 }
4990 5139
4991 5140 free(default_lp->arg);
4992 5141 free(default_lp->line);
4993 5142
4994 5143 if (default_entry == NULL) {
4995 5144 default_lp->arg = s_strdup("0");
4996 5145 } else {
4997 5146 (void) snprintf(buf, sizeof (buf), "%d",
4998 5147 default_entry->entryNum);
4999 5148 default_lp->arg = s_strdup(buf);
5000 5149 }
5001 5150
5002 5151 /*
5003 5152 * The following is required since only the line field gets
5004 5153 * written back to menu.lst
5005 5154 */
5006 5155 (void) snprintf(buf, sizeof (buf), "%s%s%s",
5007 5156 menu_cmds[DEFAULT_CMD], menu_cmds[SEP_CMD], default_lp->arg);
5008 5157 default_lp->line = s_strdup(buf);
5009 5158 }
5010 5159
5011 5160
5012 5161 static menu_t *
5013 5162 menu_read(char *menu_path)
5014 5163 {
5015 5164 FILE *fp;
5016 5165 char buf[BAM_MAXLINE], *cp;
5017 5166 menu_t *mp;
5018 5167 int line, entry, len, n;
5019 5168
5020 5169 mp = s_calloc(1, sizeof (menu_t));
5021 5170
5022 5171 fp = fopen(menu_path, "r");
5023 5172 if (fp == NULL) { /* Let the caller handle this error */
5024 5173 free(mp);
5025 5174 return (NULL);
5026 5175 }
5027 5176
5028 5177 /* Note: GRUB boot entry number starts with 0 */
5029 5178 line = LINE_INIT;
5030 5179 entry = ENTRY_INIT;
5031 5180 cp = buf;
5032 5181 len = sizeof (buf);
5033 5182 while (s_fgets(cp, len, fp) != NULL) {
5034 5183 n = strlen(cp);
5035 5184 if (cp[n - 1] == '\\') {
5036 5185 len -= n - 1;
5037 5186 assert(len >= 2);
5038 5187 cp += n - 1;
5039 5188 continue;
5040 5189 }
5041 5190 line_parser(mp, buf, &line, &entry);
5042 5191 cp = buf;
5043 5192 len = sizeof (buf);
5044 5193 }
5045 5194
5046 5195 if (fclose(fp) == EOF) {
5047 5196 bam_error(_("failed to close file: %s: %s\n"), menu_path,
5048 5197 strerror(errno));
5049 5198 }
5050 5199
5051 5200 return (mp);
5052 5201 }
5053 5202
5054 5203 static error_t
5055 5204 selector(menu_t *mp, char *opt, int *entry, char **title)
5056 5205 {
5057 5206 char *eq;
5058 5207 char *opt_dup;
5059 5208 int entryNum;
5060 5209
5061 5210 assert(mp);
5062 5211 assert(mp->start);
5063 5212 assert(opt);
5064 5213
5065 5214 opt_dup = s_strdup(opt);
5066 5215
5067 5216 if (entry)
5068 5217 *entry = ENTRY_INIT;
5069 5218 if (title)
5070 5219 *title = NULL;
5071 5220
5072 5221 eq = strchr(opt_dup, '=');
5073 5222 if (eq == NULL) {
5074 5223 bam_error(_("invalid option: %s\n"), opt);
5075 5224 free(opt_dup);
5076 5225 return (BAM_ERROR);
5077 5226 }
5078 5227
5079 5228 *eq = '\0';
5080 5229 if (entry && strcmp(opt_dup, OPT_ENTRY_NUM) == 0) {
5081 5230 assert(mp->end);
5082 5231 entryNum = s_strtol(eq + 1);
5083 5232 if (entryNum < 0 || entryNum > mp->end->entryNum) {
5084 5233 bam_error(_("invalid boot entry number: %s\n"), eq + 1);
5085 5234 free(opt_dup);
5086 5235 return (BAM_ERROR);
5087 5236 }
5088 5237 *entry = entryNum;
5089 5238 } else if (title && strcmp(opt_dup, menu_cmds[TITLE_CMD]) == 0) {
5090 5239 *title = opt + (eq - opt_dup) + 1;
5091 5240 } else {
5092 5241 bam_error(_("invalid option: %s\n"), opt);
5093 5242 free(opt_dup);
5094 5243 return (BAM_ERROR);
5095 5244 }
5096 5245
5097 5246 free(opt_dup);
5098 5247 return (BAM_SUCCESS);
5099 5248 }
5100 5249
5101 5250 /*
5102 5251 * If invoked with no titles/entries (opt == NULL)
5103 5252 * only title lines in file are printed.
5104 5253 *
5105 5254 * If invoked with a title or entry #, all
5106 5255 * lines in *every* matching entry are listed
5107 5256 */
5108 5257 static error_t
5109 5258 list_entry(menu_t *mp, char *menu_path, char *opt)
5110 5259 {
5111 5260 line_t *lp;
5112 5261 int entry = ENTRY_INIT;
5113 5262 int found;
5114 5263 char *title = NULL;
5115 5264
5116 5265 assert(mp);
5117 5266 assert(menu_path);
5118 5267
5119 5268 /* opt is optional */
5120 5269 BAM_DPRINTF(("%s: entered. args: %s %s\n", "list_entry", menu_path,
5121 5270 opt ? opt : "<NULL>"));
5122 5271
5123 5272 if (mp->start == NULL) {
5124 5273 bam_error(_("menu file not found: %s\n"), menu_path);
5125 5274 return (BAM_ERROR);
5126 5275 }
5127 5276
5128 5277 if (opt != NULL) {
5129 5278 if (selector(mp, opt, &entry, &title) != BAM_SUCCESS) {
5130 5279 return (BAM_ERROR);
5131 5280 }
5132 5281 assert((entry != ENTRY_INIT) ^ (title != NULL));
5133 5282 } else {
5134 5283 (void) read_globals(mp, menu_path, menu_cmds[DEFAULT_CMD], 0);
5135 5284 (void) read_globals(mp, menu_path, menu_cmds[TIMEOUT_CMD], 0);
5136 5285 }
5137 5286
5138 5287 found = 0;
5139 5288 for (lp = mp->start; lp; lp = lp->next) {
5140 5289 if (lp->flags == BAM_COMMENT || lp->flags == BAM_EMPTY)
5141 5290 continue;
5142 5291 if (opt == NULL && lp->flags == BAM_TITLE) {
5143 5292 bam_print(_("%d %s\n"), lp->entryNum,
5144 5293 lp->arg);
5145 5294 found = 1;
5146 5295 continue;
5147 5296 }
5148 5297 if (entry != ENTRY_INIT && lp->entryNum == entry) {
5149 5298 bam_print(_("%s\n"), lp->line);
5150 5299 found = 1;
5151 5300 continue;
5152 5301 }
5153 5302
5154 5303 /*
5155 5304 * We set the entry value here so that all lines
5156 5305 * in entry get printed. If we subsequently match
5157 5306 * title in other entries, all lines in those
5158 5307 * entries get printed as well.
5159 5308 */
5160 5309 if (title && lp->flags == BAM_TITLE && lp->arg &&
5161 5310 strncmp(title, lp->arg, strlen(title)) == 0) {
5162 5311 bam_print(_("%s\n"), lp->line);
5163 5312 entry = lp->entryNum;
5164 5313 found = 1;
5165 5314 continue;
5166 5315 }
5167 5316 }
5168 5317
5169 5318 if (!found) {
5170 5319 bam_error(_("no matching entry found\n"));
5171 5320 return (BAM_ERROR);
5172 5321 }
5173 5322
5174 5323 return (BAM_SUCCESS);
5175 5324 }
5176 5325
5177 5326 int
5178 5327 add_boot_entry(menu_t *mp,
5179 5328 char *title,
5180 5329 char *findroot,
5181 5330 char *kernel,
5182 5331 char *mod_kernel,
5183 5332 char *module,
5184 5333 char *bootfs)
5185 5334 {
5186 5335 int lineNum;
5187 5336 int entryNum;
5188 5337 char linebuf[BAM_MAXLINE];
5189 5338 menu_cmd_t k_cmd;
5190 5339 menu_cmd_t m_cmd;
5191 5340 const char *fcn = "add_boot_entry()";
5192 5341
5193 5342 assert(mp);
5194 5343
5195 5344 INJECT_ERROR1("ADD_BOOT_ENTRY_FINDROOT_NULL", findroot = NULL);
5196 5345 if (findroot == NULL) {
5197 5346 bam_error(_("can't find argument for findroot command\n"));
5198 5347 return (BAM_ERROR);
5199 5348 }
5200 5349
5201 5350 if (title == NULL) {
5202 5351 title = "Solaris"; /* default to Solaris */
5203 5352 }
5204 5353 if (kernel == NULL) {
5205 5354 bam_error(_("missing suboption: %s\n"), menu_cmds[KERNEL_CMD]);
5206 5355 return (BAM_ERROR);
5207 5356 }
5208 5357 if (module == NULL) {
5209 5358 if (bam_direct != BAM_DIRECT_DBOOT) {
5210 5359 bam_error(_("missing suboption: %s\n"),
5211 5360 menu_cmds[MODULE_CMD]);
5212 5361 return (BAM_ERROR);
5213 5362 }
5214 5363
5215 5364 /* Figure the commands out from the kernel line */
5216 5365 if (strstr(kernel, "$ISADIR") != NULL) {
5217 5366 module = DIRECT_BOOT_ARCHIVE;
5218 5367 } else if (strstr(kernel, "amd64") != NULL) {
5219 5368 module = DIRECT_BOOT_ARCHIVE_64;
5220 5369 } else {
5221 5370 module = DIRECT_BOOT_ARCHIVE_32;
5222 5371 }
5223 5372 }
5224 5373
5225 5374 k_cmd = KERNEL_DOLLAR_CMD;
5226 5375 m_cmd = MODULE_DOLLAR_CMD;
5227 5376
5228 5377 if (mp->start) {
5229 5378 lineNum = mp->end->lineNum;
5230 5379 entryNum = mp->end->entryNum;
5231 5380 } else {
5232 5381 lineNum = LINE_INIT;
5233 5382 entryNum = ENTRY_INIT;
5234 5383 }
5235 5384
5236 5385 /*
5237 5386 * No separator for comment (HDR/FTR) commands
5238 5387 * The syntax for comments is #<comment>
5239 5388 */
5240 5389 (void) snprintf(linebuf, sizeof (linebuf), "%s%s",
5241 5390 menu_cmds[COMMENT_CMD], BAM_BOOTADM_HDR);
5242 5391 line_parser(mp, linebuf, &lineNum, &entryNum);
5243 5392
5244 5393 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
5245 5394 menu_cmds[TITLE_CMD], menu_cmds[SEP_CMD], title);
5246 5395 line_parser(mp, linebuf, &lineNum, &entryNum);
5247 5396
5248 5397 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
5249 5398 menu_cmds[FINDROOT_CMD], menu_cmds[SEP_CMD], findroot);
5250 5399 line_parser(mp, linebuf, &lineNum, &entryNum);
5251 5400 BAM_DPRINTF(("%s: findroot added: line#: %d: entry#: %d\n",
5252 5401 fcn, lineNum, entryNum));
5253 5402
5254 5403 if (bootfs != NULL) {
5255 5404 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
5256 5405 menu_cmds[BOOTFS_CMD], menu_cmds[SEP_CMD], bootfs);
5257 5406 line_parser(mp, linebuf, &lineNum, &entryNum);
5258 5407 }
5259 5408
5260 5409 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
5261 5410 menu_cmds[k_cmd], menu_cmds[SEP_CMD], kernel);
5262 5411 line_parser(mp, linebuf, &lineNum, &entryNum);
5263 5412
5264 5413 if (mod_kernel != NULL) {
5265 5414 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
5266 5415 menu_cmds[m_cmd], menu_cmds[SEP_CMD], mod_kernel);
5267 5416 line_parser(mp, linebuf, &lineNum, &entryNum);
5268 5417 }
5269 5418
5270 5419 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
5271 5420 menu_cmds[m_cmd], menu_cmds[SEP_CMD], module);
5272 5421 line_parser(mp, linebuf, &lineNum, &entryNum);
5273 5422
5274 5423 (void) snprintf(linebuf, sizeof (linebuf), "%s%s",
5275 5424 menu_cmds[COMMENT_CMD], BAM_BOOTADM_FTR);
5276 5425 line_parser(mp, linebuf, &lineNum, &entryNum);
5277 5426
5278 5427 return (entryNum);
5279 5428 }
5280 5429
5281 5430 error_t
5282 5431 delete_boot_entry(menu_t *mp, int entryNum, int quiet)
5283 5432 {
5284 5433 line_t *lp;
5285 5434 line_t *freed;
5286 5435 entry_t *ent;
5287 5436 entry_t *tmp;
5288 5437 int deleted = 0;
5289 5438 const char *fcn = "delete_boot_entry()";
5290 5439
5291 5440 assert(entryNum != ENTRY_INIT);
5292 5441
5293 5442 tmp = NULL;
5294 5443
5295 5444 ent = mp->entries;
5296 5445 while (ent) {
5297 5446 lp = ent->start;
5298 5447
5299 5448 /*
5300 5449 * Check entry number and make sure it's a modifiable entry.
5301 5450 *
5302 5451 * Guidelines:
5303 5452 * + We can modify a bootadm-created entry
5304 5453 * + We can modify a libbe-created entry
5305 5454 */
5306 5455 if ((lp->flags != BAM_COMMENT &&
5307 5456 (((ent->flags & BAM_ENTRY_LIBBE) == 0) &&
5308 5457 strcmp(lp->arg, BAM_BOOTADM_HDR) != 0)) ||
5309 5458 (entryNum != ALL_ENTRIES && lp->entryNum != entryNum)) {
5310 5459 ent = ent->next;
5311 5460 continue;
5312 5461 }
5313 5462
5314 5463 /* free the entry content */
5315 5464 do {
5316 5465 freed = lp;
5317 5466 lp = lp->next; /* prev stays the same */
5318 5467 BAM_DPRINTF(("%s: freeing line: %d\n",
5319 5468 fcn, freed->lineNum));
5320 5469 unlink_line(mp, freed);
5321 5470 line_free(freed);
5322 5471 } while (freed != ent->end);
5323 5472
5324 5473 /* free the entry_t structure */
5325 5474 assert(tmp == NULL);
5326 5475 tmp = ent;
5327 5476 ent = ent->next;
5328 5477 if (tmp->prev)
5329 5478 tmp->prev->next = ent;
5330 5479 else
5331 5480 mp->entries = ent;
5332 5481 if (ent)
5333 5482 ent->prev = tmp->prev;
5334 5483 BAM_DPRINTF(("%s: freeing entry: %d\n", fcn, tmp->entryNum));
5335 5484 free(tmp);
5336 5485 tmp = NULL;
5337 5486 deleted = 1;
5338 5487 }
5339 5488
5340 5489 assert(tmp == NULL);
5341 5490
5342 5491 if (!deleted && entryNum != ALL_ENTRIES) {
5343 5492 if (quiet == DBE_PRINTERR)
5344 5493 bam_error(_("no matching bootadm entry found\n"));
5345 5494 return (BAM_ERROR);
5346 5495 }
5347 5496
5348 5497 /*
5349 5498 * Now that we have deleted an entry, update
5350 5499 * the entry numbering and the default cmd.
5351 5500 */
5352 5501 update_numbering(mp);
5353 5502
5354 5503 return (BAM_SUCCESS);
5355 5504 }
5356 5505
5357 5506 static error_t
5358 5507 delete_all_entries(menu_t *mp, char *dummy, char *opt)
5359 5508 {
5360 5509 assert(mp);
5361 5510 assert(dummy == NULL);
5362 5511 assert(opt == NULL);
5363 5512
5364 5513 BAM_DPRINTF(("%s: entered. No args\n", "delete_all_entries"));
5365 5514
5366 5515 if (mp->start == NULL) {
5367 5516 bam_print(_("the GRUB menu is empty\n"));
5368 5517 return (BAM_SUCCESS);
5369 5518 }
5370 5519
5371 5520 if (delete_boot_entry(mp, ALL_ENTRIES, DBE_PRINTERR) != BAM_SUCCESS) {
5372 5521 return (BAM_ERROR);
5373 5522 }
5374 5523
5375 5524 return (BAM_WRITE);
5376 5525 }
5377 5526
5378 5527 static FILE *
5379 5528 create_diskmap(char *osroot)
5380 5529 {
5381 5530 FILE *fp;
5382 5531 char cmd[PATH_MAX + 16];
5383 5532 char path[PATH_MAX];
5384 5533 const char *fcn = "create_diskmap()";
5385 5534
5386 5535 /* make sure we have a map file */
5387 5536 fp = fopen(GRUBDISK_MAP, "r");
5388 5537 if (fp == NULL) {
5389 5538 int ret;
5390 5539
5391 5540 ret = snprintf(path, sizeof (path), "%s/%s", osroot,
5392 5541 CREATE_DISKMAP);
5393 5542 if (ret >= sizeof (path)) {
5394 5543 bam_error(_("unable to create path on mountpoint %s, "
5395 5544 "path too long\n"), osroot);
5396 5545 return (NULL);
5397 5546 }
5398 5547 if (is_safe_exec(path) == BAM_ERROR)
5399 5548 return (NULL);
5400 5549
5401 5550 (void) snprintf(cmd, sizeof (cmd),
5402 5551 "%s/%s > /dev/null", osroot, CREATE_DISKMAP);
5403 5552 if (exec_cmd(cmd, NULL) != 0)
5404 5553 return (NULL);
5405 5554 fp = fopen(GRUBDISK_MAP, "r");
5406 5555 INJECT_ERROR1("DISKMAP_CREATE_FAIL", fp = NULL);
5407 5556 if (fp) {
5408 5557 BAM_DPRINTF(("%s: created diskmap file: %s\n",
5409 5558 fcn, GRUBDISK_MAP));
5410 5559 } else {
5411 5560 BAM_DPRINTF(("%s: FAILED to create diskmap file: %s\n",
5412 5561 fcn, GRUBDISK_MAP));
5413 5562 }
5414 5563 }
5415 5564 return (fp);
5416 5565 }
5417 5566
5418 5567 #define SECTOR_SIZE 512
5419 5568
5420 5569 static int
5421 5570 get_partition(char *device)
5422 5571 {
5423 5572 int i, fd, is_pcfs, partno = PARTNO_NOTFOUND;
5424 5573 struct mboot *mboot;
5425 5574 char boot_sect[SECTOR_SIZE];
5426 5575 char *wholedisk, *slice;
5427 5576 #ifdef i386
5428 5577 ext_part_t *epp;
5429 5578 uint32_t secnum, numsec;
5430 5579 int rval, pno, ext_partno = PARTNO_NOTFOUND;
5431 5580 #endif
5432 5581
5433 5582 /* form whole disk (p0) */
5434 5583 slice = device + strlen(device) - 2;
5435 5584 is_pcfs = (*slice != 's');
5436 5585 if (!is_pcfs)
5437 5586 *slice = '\0';
5438 5587 wholedisk = s_calloc(1, strlen(device) + 3);
5439 5588 (void) snprintf(wholedisk, strlen(device) + 3, "%sp0", device);
5440 5589 if (!is_pcfs)
5441 5590 *slice = 's';
5442 5591
5443 5592 /* read boot sector */
5444 5593 fd = open(wholedisk, O_RDONLY);
5445 5594 if (fd == -1 || read(fd, boot_sect, SECTOR_SIZE) != SECTOR_SIZE) {
5446 5595 return (partno);
5447 5596 }
5448 5597 (void) close(fd);
5449 5598
5450 5599 #ifdef i386
5451 5600 /* Read/Initialize extended partition information */
5452 5601 if ((rval = libfdisk_init(&epp, wholedisk, NULL, FDISK_READ_DISK))
5453 5602 != FDISK_SUCCESS) {
5454 5603 switch (rval) {
5455 5604 /*
5456 5605 * FDISK_EBADLOGDRIVE and FDISK_ENOLOGDRIVE can
5457 5606 * be considered as soft errors and hence
5458 5607 * we do not return
5459 5608 */
5460 5609 case FDISK_EBADLOGDRIVE:
5461 5610 break;
5462 5611 case FDISK_ENOLOGDRIVE:
5463 5612 break;
5464 5613 case FDISK_EBADMAGIC:
5465 5614 /*FALLTHROUGH*/
5466 5615 default:
5467 5616 free(wholedisk);
5468 5617 libfdisk_fini(&epp);
5469 5618 return (partno);
5470 5619 }
5471 5620 }
5472 5621 #endif
5473 5622 free(wholedisk);
5474 5623
5475 5624 /* parse fdisk table */
5476 5625 mboot = (struct mboot *)((void *)boot_sect);
5477 5626 for (i = 0; i < FD_NUMPART; i++) {
5478 5627 struct ipart *part =
5479 5628 (struct ipart *)(uintptr_t)mboot->parts + i;
5480 5629 if (is_pcfs) { /* looking for solaris boot part */
5481 5630 if (part->systid == 0xbe) {
5482 5631 partno = i;
5483 5632 break;
5484 5633 }
5485 5634 } else { /* look for solaris partition, old and new */
5486 5635 if (part->systid == EFI_PMBR) {
5487 5636 partno = PARTNO_EFI;
5488 5637 break;
5489 5638 }
5490 5639
5491 5640 #ifdef i386
5492 5641 if ((part->systid == SUNIXOS &&
5493 5642 (fdisk_is_linux_swap(epp, part->relsect,
5494 5643 NULL) != 0)) || part->systid == SUNIXOS2) {
5495 5644 #else
5496 5645 if (part->systid == SUNIXOS ||
5497 5646 part->systid == SUNIXOS2) {
5498 5647 #endif
5499 5648 partno = i;
5500 5649 break;
5501 5650 }
5502 5651
5503 5652 #ifdef i386
5504 5653 if (fdisk_is_dos_extended(part->systid))
5505 5654 ext_partno = i;
5506 5655 #endif
5507 5656 }
5508 5657 }
5509 5658 #ifdef i386
5510 5659 /* If no primary solaris partition, check extended partition */
5511 5660 if ((partno == PARTNO_NOTFOUND) && (ext_partno != PARTNO_NOTFOUND)) {
5512 5661 rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec);
5513 5662 if (rval == FDISK_SUCCESS) {
5514 5663 partno = pno - 1;
5515 5664 }
5516 5665 }
5517 5666 libfdisk_fini(&epp);
5518 5667 #endif
5519 5668 return (partno);
5520 5669 }
5521 5670
5522 5671 char *
5523 5672 get_grubroot(char *osroot, char *osdev, char *menu_root)
5524 5673 {
5525 5674 char *grubroot; /* (hd#,#,#) */
5526 5675 char *slice;
5527 5676 char *grubhd = NULL;
5528 5677 int fdiskpart;
5529 5678 int found = 0;
5530 5679 char *devname;
5531 5680 char *ctdname = strstr(osdev, "dsk/");
5532 5681 char linebuf[PATH_MAX];
5533 5682 FILE *fp;
5534 5683
5535 5684 INJECT_ERROR1("GRUBROOT_INVALID_OSDEV", ctdname = NULL);
5536 5685 if (ctdname == NULL) {
5537 5686 bam_error(_("not a /dev/[r]dsk name: %s\n"), osdev);
5538 5687 return (NULL);
5539 5688 }
5540 5689
5541 5690 if (menu_root && !menu_on_bootdisk(osroot, menu_root)) {
5542 5691 /* menu bears no resemblance to our reality */
5543 5692 bam_error(_("cannot get (hd?,?,?) for menu. menu not on "
5544 5693 "bootdisk: %s\n"), osdev);
5545 5694 return (NULL);
5546 5695 }
5547 5696
5548 5697 ctdname += strlen("dsk/");
5549 5698 slice = strrchr(ctdname, 's');
5550 5699 if (slice)
5551 5700 *slice = '\0';
5552 5701
5553 5702 fp = create_diskmap(osroot);
5554 5703 if (fp == NULL) {
5555 5704 bam_error(_("create_diskmap command failed for OS root: %s.\n"),
5556 5705 osroot);
5557 5706 return (NULL);
5558 5707 }
5559 5708
5560 5709 rewind(fp);
5561 5710 while (s_fgets(linebuf, sizeof (linebuf), fp) != NULL) {
5562 5711 grubhd = strtok(linebuf, " \t\n");
5563 5712 if (grubhd)
5564 5713 devname = strtok(NULL, " \t\n");
5565 5714 else
5566 5715 devname = NULL;
5567 5716 if (devname && strcmp(devname, ctdname) == 0) {
5568 5717 found = 1;
5569 5718 break;
5570 5719 }
5571 5720 }
5572 5721
5573 5722 if (slice)
5574 5723 *slice = 's';
5575 5724
5576 5725 (void) fclose(fp);
5577 5726 fp = NULL;
5578 5727
5579 5728 INJECT_ERROR1("GRUBROOT_BIOSDEV_FAIL", found = 0);
5580 5729 if (found == 0) {
5581 5730 bam_error(_("not using biosdev command for disk: %s.\n"),
5582 5731 osdev);
5583 5732 return (NULL);
5584 5733 }
5585 5734
5586 5735 fdiskpart = get_partition(osdev);
5587 5736 INJECT_ERROR1("GRUBROOT_FDISK_FAIL", fdiskpart = PARTNO_NOTFOUND);
5588 5737 if (fdiskpart == PARTNO_NOTFOUND) {
5589 5738 bam_error(_("failed to determine fdisk partition: %s\n"),
5590 5739 osdev);
5591 5740 return (NULL);
5592 5741 }
5593 5742
5594 5743 grubroot = s_calloc(1, 10);
5595 5744 if (fdiskpart == PARTNO_EFI) {
5596 5745 fdiskpart = atoi(&slice[1]);
5597 5746 slice = NULL;
5598 5747 }
5599 5748
5600 5749 if (slice) {
5601 5750 (void) snprintf(grubroot, 10, "(hd%s,%d,%c)",
5602 5751 grubhd, fdiskpart, slice[1] + 'a' - '0');
5603 5752 } else
5604 5753 (void) snprintf(grubroot, 10, "(hd%s,%d)",
5605 5754 grubhd, fdiskpart);
5606 5755
5607 5756 assert(fp == NULL);
5608 5757 assert(strncmp(grubroot, "(hd", strlen("(hd")) == 0);
5609 5758 return (grubroot);
5610 5759 }
5611 5760
5612 5761 static char *
5613 5762 find_primary_common(char *mntpt, char *fstype)
5614 5763 {
5615 5764 char signdir[PATH_MAX];
5616 5765 char tmpsign[MAXNAMELEN + 1];
5617 5766 char *lu;
5618 5767 char *ufs;
5619 5768 char *zfs;
5620 5769 DIR *dirp = NULL;
5621 5770 struct dirent *entp;
5622 5771 struct stat sb;
5623 5772 const char *fcn = "find_primary_common()";
5624 5773
5625 5774 (void) snprintf(signdir, sizeof (signdir), "%s/%s",
5626 5775 mntpt, GRUBSIGN_DIR);
5627 5776
5628 5777 if (stat(signdir, &sb) == -1) {
5629 5778 BAM_DPRINTF(("%s: no sign dir: %s\n", fcn, signdir));
5630 5779 return (NULL);
5631 5780 }
5632 5781
5633 5782 dirp = opendir(signdir);
5634 5783 INJECT_ERROR1("SIGNDIR_OPENDIR_FAIL", dirp = NULL);
5635 5784 if (dirp == NULL) {
5636 5785 bam_error(_("opendir of %s failed: %s\n"), signdir,
5637 5786 strerror(errno));
5638 5787 return (NULL);
5639 5788 }
5640 5789
5641 5790 ufs = zfs = lu = NULL;
5642 5791
5643 5792 while ((entp = readdir(dirp)) != NULL) {
5644 5793 if (strcmp(entp->d_name, ".") == 0 ||
5645 5794 strcmp(entp->d_name, "..") == 0)
5646 5795 continue;
5647 5796
5648 5797 (void) snprintf(tmpsign, sizeof (tmpsign), "%s", entp->d_name);
5649 5798
5650 5799 if (lu == NULL &&
5651 5800 strncmp(tmpsign, GRUBSIGN_LU_PREFIX,
5652 5801 strlen(GRUBSIGN_LU_PREFIX)) == 0) {
5653 5802 lu = s_strdup(tmpsign);
5654 5803 }
5655 5804
5656 5805 if (ufs == NULL &&
5657 5806 strncmp(tmpsign, GRUBSIGN_UFS_PREFIX,
5658 5807 strlen(GRUBSIGN_UFS_PREFIX)) == 0) {
5659 5808 ufs = s_strdup(tmpsign);
5660 5809 }
5661 5810
5662 5811 if (zfs == NULL &&
5663 5812 strncmp(tmpsign, GRUBSIGN_ZFS_PREFIX,
5664 5813 strlen(GRUBSIGN_ZFS_PREFIX)) == 0) {
5665 5814 zfs = s_strdup(tmpsign);
5666 5815 }
5667 5816 }
5668 5817
5669 5818 BAM_DPRINTF(("%s: existing primary signs: zfs=%s ufs=%s lu=%s\n", fcn,
5670 5819 zfs ? zfs : "NULL",
5671 5820 ufs ? ufs : "NULL",
5672 5821 lu ? lu : "NULL"));
5673 5822
5674 5823 if (dirp) {
5675 5824 (void) closedir(dirp);
5676 5825 dirp = NULL;
5677 5826 }
5678 5827
5679 5828 if (strcmp(fstype, "ufs") == 0 && zfs) {
5680 5829 bam_error(_("found mismatched boot signature %s for "
5681 5830 "filesystem type: %s.\n"), zfs, "ufs");
5682 5831 free(zfs);
5683 5832 zfs = NULL;
5684 5833 } else if (strcmp(fstype, "zfs") == 0 && ufs) {
5685 5834 bam_error(_("found mismatched boot signature %s for "
5686 5835 "filesystem type: %s.\n"), ufs, "zfs");
5687 5836 free(ufs);
5688 5837 ufs = NULL;
5689 5838 }
5690 5839
5691 5840 assert(dirp == NULL);
5692 5841
5693 5842 /* For now, we let Live Upgrade take care of its signature itself */
5694 5843 if (lu) {
5695 5844 BAM_DPRINTF(("%s: feeing LU sign: %s\n", fcn, lu));
5696 5845 free(lu);
5697 5846 lu = NULL;
5698 5847 }
5699 5848
5700 5849 return (zfs ? zfs : ufs);
5701 5850 }
5702 5851
5703 5852 static char *
5704 5853 find_backup_common(char *mntpt, char *fstype)
5705 5854 {
5706 5855 FILE *bfp = NULL;
5707 5856 char tmpsign[MAXNAMELEN + 1];
5708 5857 char backup[PATH_MAX];
5709 5858 char *ufs;
5710 5859 char *zfs;
5711 5860 char *lu;
5712 5861 int error;
5713 5862 const char *fcn = "find_backup_common()";
5714 5863
5715 5864 /*
5716 5865 * We didn't find it in the primary directory.
5717 5866 * Look at the backup
5718 5867 */
5719 5868 (void) snprintf(backup, sizeof (backup), "%s%s",
5720 5869 mntpt, GRUBSIGN_BACKUP);
5721 5870
5722 5871 bfp = fopen(backup, "r");
5723 5872 if (bfp == NULL) {
5724 5873 error = errno;
5725 5874 if (bam_verbose) {
5726 5875 bam_error(_("failed to open file: %s: %s\n"),
5727 5876 backup, strerror(error));
5728 5877 }
5729 5878 BAM_DPRINTF(("%s: failed to open %s: %s\n",
5730 5879 fcn, backup, strerror(error)));
5731 5880 return (NULL);
5732 5881 }
5733 5882
5734 5883 ufs = zfs = lu = NULL;
5735 5884
5736 5885 while (s_fgets(tmpsign, sizeof (tmpsign), bfp) != NULL) {
5737 5886
5738 5887 if (lu == NULL &&
5739 5888 strncmp(tmpsign, GRUBSIGN_LU_PREFIX,
5740 5889 strlen(GRUBSIGN_LU_PREFIX)) == 0) {
5741 5890 lu = s_strdup(tmpsign);
5742 5891 }
5743 5892
5744 5893 if (ufs == NULL &&
5745 5894 strncmp(tmpsign, GRUBSIGN_UFS_PREFIX,
5746 5895 strlen(GRUBSIGN_UFS_PREFIX)) == 0) {
5747 5896 ufs = s_strdup(tmpsign);
5748 5897 }
5749 5898
5750 5899 if (zfs == NULL &&
5751 5900 strncmp(tmpsign, GRUBSIGN_ZFS_PREFIX,
5752 5901 strlen(GRUBSIGN_ZFS_PREFIX)) == 0) {
5753 5902 zfs = s_strdup(tmpsign);
5754 5903 }
5755 5904 }
5756 5905
5757 5906 BAM_DPRINTF(("%s: existing backup signs: zfs=%s ufs=%s lu=%s\n", fcn,
5758 5907 zfs ? zfs : "NULL",
5759 5908 ufs ? ufs : "NULL",
5760 5909 lu ? lu : "NULL"));
5761 5910
5762 5911 if (bfp) {
5763 5912 (void) fclose(bfp);
5764 5913 bfp = NULL;
5765 5914 }
5766 5915
5767 5916 if (strcmp(fstype, "ufs") == 0 && zfs) {
5768 5917 bam_error(_("found mismatched boot signature %s for "
5769 5918 "filesystem type: %s.\n"), zfs, "ufs");
5770 5919 free(zfs);
5771 5920 zfs = NULL;
5772 5921 } else if (strcmp(fstype, "zfs") == 0 && ufs) {
5773 5922 bam_error(_("found mismatched boot signature %s for "
5774 5923 "filesystem type: %s.\n"), ufs, "zfs");
5775 5924 free(ufs);
5776 5925 ufs = NULL;
5777 5926 }
5778 5927
5779 5928 assert(bfp == NULL);
5780 5929
5781 5930 /* For now, we let Live Upgrade take care of its signature itself */
5782 5931 if (lu) {
5783 5932 BAM_DPRINTF(("%s: feeing LU sign: %s\n", fcn, lu));
5784 5933 free(lu);
5785 5934 lu = NULL;
5786 5935 }
5787 5936
5788 5937 return (zfs ? zfs : ufs);
5789 5938 }
5790 5939
5791 5940 static char *
5792 5941 find_ufs_existing(char *osroot)
5793 5942 {
5794 5943 char *sign;
5795 5944 const char *fcn = "find_ufs_existing()";
5796 5945
5797 5946 sign = find_primary_common(osroot, "ufs");
5798 5947 if (sign == NULL) {
5799 5948 sign = find_backup_common(osroot, "ufs");
5800 5949 BAM_DPRINTF(("%s: existing backup sign: %s\n", fcn,
5801 5950 sign ? sign : "NULL"));
5802 5951 } else {
5803 5952 BAM_DPRINTF(("%s: existing primary sign: %s\n", fcn, sign));
5804 5953 }
5805 5954
5806 5955 return (sign);
5807 5956 }
5808 5957
5809 5958 char *
5810 5959 get_mountpoint(char *special, char *fstype)
5811 5960 {
5812 5961 FILE *mntfp;
5813 5962 struct mnttab mp = {0};
5814 5963 struct mnttab mpref = {0};
5815 5964 int error;
5816 5965 int ret;
5817 5966 const char *fcn = "get_mountpoint()";
5818 5967
5819 5968 BAM_DPRINTF(("%s: entered. args: %s %s\n", fcn, special, fstype));
5820 5969
5821 5970 mntfp = fopen(MNTTAB, "r");
5822 5971 error = errno;
5823 5972 INJECT_ERROR1("MNTTAB_ERR_GET_MNTPT", mntfp = NULL);
5824 5973 if (mntfp == NULL) {
5825 5974 bam_error(_("failed to open file: %s: %s\n"),
5826 5975 MNTTAB, strerror(error));
5827 5976 return (NULL);
5828 5977 }
5829 5978
5830 5979 mpref.mnt_special = special;
5831 5980 mpref.mnt_fstype = fstype;
5832 5981
5833 5982 ret = getmntany(mntfp, &mp, &mpref);
5834 5983 INJECT_ERROR1("GET_MOUNTPOINT_MNTANY", ret = 1);
5835 5984 if (ret != 0) {
5836 5985 (void) fclose(mntfp);
5837 5986 BAM_DPRINTF(("%s: no mount-point for special=%s and "
5838 5987 "fstype=%s\n", fcn, special, fstype));
5839 5988 return (NULL);
5840 5989 }
5841 5990 (void) fclose(mntfp);
5842 5991
5843 5992 assert(mp.mnt_mountp);
5844 5993
5845 5994 BAM_DPRINTF(("%s: returning mount-point for special %s: %s\n",
5846 5995 fcn, special, mp.mnt_mountp));
5847 5996
5848 5997 return (s_strdup(mp.mnt_mountp));
5849 5998 }
5850 5999
5851 6000 /*
5852 6001 * Mounts a "legacy" top dataset (if needed)
5853 6002 * Returns: The mountpoint of the legacy top dataset or NULL on error
5854 6003 * mnted returns one of the above values defined for zfs_mnted_t
5855 6004 */
5856 6005 static char *
5857 6006 mount_legacy_dataset(char *pool, zfs_mnted_t *mnted)
5858 6007 {
5859 6008 char cmd[PATH_MAX];
5860 6009 char tmpmnt[PATH_MAX];
5861 6010 filelist_t flist = {0};
5862 6011 char *is_mounted;
5863 6012 struct stat sb;
5864 6013 int ret;
5865 6014 const char *fcn = "mount_legacy_dataset()";
5866 6015
5867 6016 BAM_DPRINTF(("%s: entered. arg: %s\n", fcn, pool));
5868 6017
5869 6018 *mnted = ZFS_MNT_ERROR;
5870 6019
5871 6020 (void) snprintf(cmd, sizeof (cmd),
5872 6021 "/sbin/zfs get -Ho value mounted %s",
5873 6022 pool);
5874 6023
5875 6024 ret = exec_cmd(cmd, &flist);
5876 6025 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_CMD", ret = 1);
5877 6026 if (ret != 0) {
5878 6027 bam_error(_("failed to determine mount status of ZFS "
5879 6028 "pool %s\n"), pool);
5880 6029 return (NULL);
5881 6030 }
5882 6031
5883 6032 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_OUT", flist.head = NULL);
5884 6033 if ((flist.head == NULL) || (flist.head != flist.tail)) {
5885 6034 bam_error(_("ZFS pool %s has bad mount status\n"), pool);
5886 6035 filelist_free(&flist);
5887 6036 return (NULL);
5888 6037 }
5889 6038
5890 6039 is_mounted = strtok(flist.head->line, " \t\n");
5891 6040 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_YES", is_mounted = "yes");
5892 6041 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_NO", is_mounted = "no");
5893 6042 if (strcmp(is_mounted, "no") != 0) {
5894 6043 filelist_free(&flist);
5895 6044 *mnted = LEGACY_ALREADY;
5896 6045 /* get_mountpoint returns a strdup'ed string */
5897 6046 BAM_DPRINTF(("%s: legacy pool %s already mounted\n",
5898 6047 fcn, pool));
5899 6048 return (get_mountpoint(pool, "zfs"));
5900 6049 }
5901 6050
5902 6051 filelist_free(&flist);
5903 6052
5904 6053 /*
5905 6054 * legacy top dataset is not mounted. Mount it now
5906 6055 * First create a mountpoint.
5907 6056 */
5908 6057 (void) snprintf(tmpmnt, sizeof (tmpmnt), "%s.%d",
5909 6058 ZFS_LEGACY_MNTPT, getpid());
5910 6059
5911 6060 ret = stat(tmpmnt, &sb);
5912 6061 if (ret == -1) {
5913 6062 BAM_DPRINTF(("%s: legacy pool %s mount-point %s absent\n",
5914 6063 fcn, pool, tmpmnt));
5915 6064 ret = mkdirp(tmpmnt, DIR_PERMS);
5916 6065 INJECT_ERROR1("Z_MOUNT_TOP_LEG_MNTPT_MKDIRP", ret = -1);
5917 6066 if (ret == -1) {
5918 6067 bam_error(_("mkdir of %s failed: %s\n"), tmpmnt,
5919 6068 strerror(errno));
5920 6069 return (NULL);
5921 6070 }
5922 6071 } else {
5923 6072 BAM_DPRINTF(("%s: legacy pool %s mount-point %s is already "
5924 6073 "present\n", fcn, pool, tmpmnt));
5925 6074 }
5926 6075
5927 6076 (void) snprintf(cmd, sizeof (cmd),
5928 6077 "/sbin/mount -F zfs %s %s",
5929 6078 pool, tmpmnt);
5930 6079
5931 6080 ret = exec_cmd(cmd, NULL);
5932 6081 INJECT_ERROR1("Z_MOUNT_TOP_LEG_MOUNT_CMD", ret = 1);
5933 6082 if (ret != 0) {
5934 6083 bam_error(_("mount of ZFS pool %s failed\n"), pool);
5935 6084 (void) rmdir(tmpmnt);
5936 6085 return (NULL);
5937 6086 }
5938 6087
5939 6088 *mnted = LEGACY_MOUNTED;
5940 6089 BAM_DPRINTF(("%s: legacy pool %s successfully mounted at %s\n",
5941 6090 fcn, pool, tmpmnt));
5942 6091 return (s_strdup(tmpmnt));
5943 6092 }
5944 6093
5945 6094 /*
5946 6095 * Mounts the top dataset (if needed)
5947 6096 * Returns: The mountpoint of the top dataset or NULL on error
5948 6097 * mnted returns one of the above values defined for zfs_mnted_t
5949 6098 */
5950 6099 char *
5951 6100 mount_top_dataset(char *pool, zfs_mnted_t *mnted)
5952 6101 {
5953 6102 char cmd[PATH_MAX];
5954 6103 filelist_t flist = {0};
5955 6104 char *is_mounted;
5956 6105 char *mntpt;
5957 6106 char *zmntpt;
5958 6107 int ret;
5959 6108 const char *fcn = "mount_top_dataset()";
5960 6109
5961 6110 *mnted = ZFS_MNT_ERROR;
5962 6111
5963 6112 BAM_DPRINTF(("%s: entered. arg: %s\n", fcn, pool));
5964 6113
5965 6114 /*
5966 6115 * First check if the top dataset is a "legacy" dataset
5967 6116 */
5968 6117 (void) snprintf(cmd, sizeof (cmd),
5969 6118 "/sbin/zfs get -Ho value mountpoint %s",
5970 6119 pool);
5971 6120 ret = exec_cmd(cmd, &flist);
5972 6121 INJECT_ERROR1("Z_MOUNT_TOP_GET_MNTPT", ret = 1);
5973 6122 if (ret != 0) {
5974 6123 bam_error(_("failed to determine mount point of ZFS pool %s\n"),
5975 6124 pool);
5976 6125 return (NULL);
5977 6126 }
5978 6127
5979 6128 if (flist.head && (flist.head == flist.tail)) {
5980 6129 char *legacy = strtok(flist.head->line, " \t\n");
5981 6130 if (legacy && strcmp(legacy, "legacy") == 0) {
5982 6131 filelist_free(&flist);
5983 6132 BAM_DPRINTF(("%s: is legacy, pool=%s\n", fcn, pool));
5984 6133 return (mount_legacy_dataset(pool, mnted));
5985 6134 }
5986 6135 }
5987 6136
5988 6137 filelist_free(&flist);
5989 6138
5990 6139 BAM_DPRINTF(("%s: is *NOT* legacy, pool=%s\n", fcn, pool));
5991 6140
5992 6141 (void) snprintf(cmd, sizeof (cmd),
5993 6142 "/sbin/zfs get -Ho value mounted %s",
5994 6143 pool);
5995 6144
5996 6145 ret = exec_cmd(cmd, &flist);
5997 6146 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED", ret = 1);
5998 6147 if (ret != 0) {
5999 6148 bam_error(_("failed to determine mount status of ZFS "
6000 6149 "pool %s\n"), pool);
6001 6150 return (NULL);
6002 6151 }
6003 6152
6004 6153 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_VAL", flist.head = NULL);
6005 6154 if ((flist.head == NULL) || (flist.head != flist.tail)) {
6006 6155 bam_error(_("ZFS pool %s has bad mount status\n"), pool);
6007 6156 filelist_free(&flist);
6008 6157 return (NULL);
6009 6158 }
6010 6159
6011 6160 is_mounted = strtok(flist.head->line, " \t\n");
6012 6161 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_YES", is_mounted = "yes");
6013 6162 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_NO", is_mounted = "no");
6014 6163 if (strcmp(is_mounted, "no") != 0) {
6015 6164 filelist_free(&flist);
6016 6165 *mnted = ZFS_ALREADY;
6017 6166 BAM_DPRINTF(("%s: non-legacy pool %s mounted already\n",
6018 6167 fcn, pool));
6019 6168 goto mounted;
6020 6169 }
6021 6170
6022 6171 filelist_free(&flist);
6023 6172 BAM_DPRINTF(("%s: non-legacy pool %s *NOT* already mounted\n",
6024 6173 fcn, pool));
6025 6174
6026 6175 /* top dataset is not mounted. Mount it now */
6027 6176 (void) snprintf(cmd, sizeof (cmd),
6028 6177 "/sbin/zfs mount %s", pool);
6029 6178 ret = exec_cmd(cmd, NULL);
6030 6179 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_MOUNT_CMD", ret = 1);
6031 6180 if (ret != 0) {
6032 6181 bam_error(_("mount of ZFS pool %s failed\n"), pool);
6033 6182 return (NULL);
6034 6183 }
6035 6184 *mnted = ZFS_MOUNTED;
6036 6185 BAM_DPRINTF(("%s: non-legacy pool %s mounted now\n", fcn, pool));
6037 6186 /*FALLTHRU*/
6038 6187 mounted:
6039 6188 /*
6040 6189 * Now get the mountpoint
6041 6190 */
6042 6191 (void) snprintf(cmd, sizeof (cmd),
6043 6192 "/sbin/zfs get -Ho value mountpoint %s",
6044 6193 pool);
6045 6194
6046 6195 ret = exec_cmd(cmd, &flist);
6047 6196 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_CMD", ret = 1);
6048 6197 if (ret != 0) {
6049 6198 bam_error(_("failed to determine mount point of ZFS pool %s\n"),
6050 6199 pool);
6051 6200 goto error;
6052 6201 }
6053 6202
6054 6203 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_OUT", flist.head = NULL);
6055 6204 if ((flist.head == NULL) || (flist.head != flist.tail)) {
6056 6205 bam_error(_("ZFS pool %s has no mount-point\n"), pool);
6057 6206 goto error;
6058 6207 }
6059 6208
6060 6209 mntpt = strtok(flist.head->line, " \t\n");
6061 6210 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_STRTOK", mntpt = "foo");
6062 6211 if (*mntpt != '/') {
6063 6212 bam_error(_("ZFS pool %s has bad mount-point %s\n"),
6064 6213 pool, mntpt);
6065 6214 goto error;
6066 6215 }
6067 6216 zmntpt = s_strdup(mntpt);
6068 6217
6069 6218 filelist_free(&flist);
6070 6219
6071 6220 BAM_DPRINTF(("%s: non-legacy pool %s is mounted at %s\n",
6072 6221 fcn, pool, zmntpt));
6073 6222
6074 6223 return (zmntpt);
6075 6224
6076 6225 error:
6077 6226 filelist_free(&flist);
6078 6227 (void) umount_top_dataset(pool, *mnted, NULL);
6079 6228 BAM_DPRINTF(("%s: returning FAILURE\n", fcn));
6080 6229 return (NULL);
6081 6230 }
6082 6231
6083 6232 int
6084 6233 umount_top_dataset(char *pool, zfs_mnted_t mnted, char *mntpt)
6085 6234 {
6086 6235 char cmd[PATH_MAX];
6087 6236 int ret;
6088 6237 const char *fcn = "umount_top_dataset()";
6089 6238
6090 6239 INJECT_ERROR1("Z_UMOUNT_TOP_INVALID_STATE", mnted = ZFS_MNT_ERROR);
6091 6240 switch (mnted) {
6092 6241 case LEGACY_ALREADY:
6093 6242 case ZFS_ALREADY:
6094 6243 /* nothing to do */
6095 6244 BAM_DPRINTF(("%s: pool %s was already mounted at %s, Nothing "
6096 6245 "to umount\n", fcn, pool, mntpt ? mntpt : "NULL"));
6097 6246 free(mntpt);
6098 6247 return (BAM_SUCCESS);
6099 6248 case LEGACY_MOUNTED:
6100 6249 (void) snprintf(cmd, sizeof (cmd),
6101 6250 "/sbin/umount %s", pool);
6102 6251 ret = exec_cmd(cmd, NULL);
6103 6252 INJECT_ERROR1("Z_UMOUNT_TOP_LEGACY_UMOUNT_FAIL", ret = 1);
6104 6253 if (ret != 0) {
6105 6254 bam_error(_("umount of %s failed\n"), pool);
6106 6255 free(mntpt);
6107 6256 return (BAM_ERROR);
6108 6257 }
6109 6258 if (mntpt)
6110 6259 (void) rmdir(mntpt);
6111 6260 free(mntpt);
6112 6261 BAM_DPRINTF(("%s: legacy pool %s was mounted by us, "
6113 6262 "successfully unmounted\n", fcn, pool));
6114 6263 return (BAM_SUCCESS);
6115 6264 case ZFS_MOUNTED:
6116 6265 free(mntpt);
6117 6266 (void) snprintf(cmd, sizeof (cmd),
6118 6267 "/sbin/zfs unmount %s", pool);
6119 6268 ret = exec_cmd(cmd, NULL);
6120 6269 INJECT_ERROR1("Z_UMOUNT_TOP_NONLEG_UMOUNT_FAIL", ret = 1);
6121 6270 if (ret != 0) {
6122 6271 bam_error(_("umount of %s failed\n"), pool);
6123 6272 return (BAM_ERROR);
6124 6273 }
6125 6274 BAM_DPRINTF(("%s: nonleg pool %s was mounted by us, "
6126 6275 "successfully unmounted\n", fcn, pool));
6127 6276 return (BAM_SUCCESS);
6128 6277 default:
6129 6278 bam_error(_("Internal error: bad saved mount state for "
6130 6279 "pool %s\n"), pool);
6131 6280 return (BAM_ERROR);
6132 6281 }
6133 6282 /*NOTREACHED*/
6134 6283 }
6135 6284
6136 6285 /*
6137 6286 * For ZFS, osdev can be one of two forms
6138 6287 * It can be a "special" file as seen in mnttab: rpool/ROOT/szboot_0402
6139 6288 * It can be a /dev/[r]dsk special file. We handle both instances
6140 6289 */
6141 6290 static char *
6142 6291 get_pool(char *osdev)
6143 6292 {
6144 6293 char cmd[PATH_MAX];
6145 6294 char buf[PATH_MAX];
6146 6295 filelist_t flist = {0};
6147 6296 char *pool;
6148 6297 char *cp;
6149 6298 char *slash;
6150 6299 int ret;
6151 6300 const char *fcn = "get_pool()";
6152 6301
6153 6302 INJECT_ERROR1("GET_POOL_OSDEV", osdev = NULL);
6154 6303 if (osdev == NULL) {
6155 6304 bam_error(_("NULL device: cannot determine pool name\n"));
6156 6305 return (NULL);
6157 6306 }
6158 6307
6159 6308 BAM_DPRINTF(("%s: osdev arg = %s\n", fcn, osdev));
6160 6309
6161 6310 if (osdev[0] != '/') {
6162 6311 (void) strlcpy(buf, osdev, sizeof (buf));
6163 6312 slash = strchr(buf, '/');
6164 6313 if (slash)
6165 6314 *slash = '\0';
6166 6315 pool = s_strdup(buf);
6167 6316 BAM_DPRINTF(("%s: got pool. pool = %s\n", fcn, pool));
6168 6317 return (pool);
6169 6318 } else if (strncmp(osdev, "/dev/dsk/", strlen("/dev/dsk/")) != 0 &&
6170 6319 strncmp(osdev, "/dev/rdsk/", strlen("/dev/rdsk/")) != 0) {
6171 6320 bam_error(_("invalid device %s: cannot determine pool name\n"),
6172 6321 osdev);
6173 6322 return (NULL);
6174 6323 }
6175 6324
6176 6325 /*
6177 6326 * Call the zfs fstyp directly since this is a zpool. This avoids
6178 6327 * potential pcfs conflicts if the first block wasn't cleared.
6179 6328 */
6180 6329 (void) snprintf(cmd, sizeof (cmd),
6181 6330 "/usr/lib/fs/zfs/fstyp -a %s 2>/dev/null | /bin/grep '^name:'",
6182 6331 osdev);
6183 6332
6184 6333 ret = exec_cmd(cmd, &flist);
6185 6334 INJECT_ERROR1("GET_POOL_FSTYP", ret = 1);
6186 6335 if (ret != 0) {
6187 6336 bam_error(_("fstyp -a on device %s failed\n"), osdev);
6188 6337 return (NULL);
6189 6338 }
6190 6339
6191 6340 INJECT_ERROR1("GET_POOL_FSTYP_OUT", flist.head = NULL);
6192 6341 if ((flist.head == NULL) || (flist.head != flist.tail)) {
6193 6342 bam_error(_("NULL fstyp -a output for device %s\n"), osdev);
6194 6343 filelist_free(&flist);
6195 6344 return (NULL);
6196 6345 }
6197 6346
6198 6347 (void) strtok(flist.head->line, "'");
6199 6348 cp = strtok(NULL, "'");
6200 6349 INJECT_ERROR1("GET_POOL_FSTYP_STRTOK", cp = NULL);
6201 6350 if (cp == NULL) {
6202 6351 bam_error(_("bad fstyp -a output for device %s\n"), osdev);
6203 6352 filelist_free(&flist);
6204 6353 return (NULL);
6205 6354 }
6206 6355
6207 6356 pool = s_strdup(cp);
6208 6357
6209 6358 filelist_free(&flist);
6210 6359
6211 6360 BAM_DPRINTF(("%s: got pool. pool = %s\n", fcn, pool));
6212 6361
6213 6362 return (pool);
6214 6363 }
6215 6364
6216 6365 static char *
6217 6366 find_zfs_existing(char *osdev)
6218 6367 {
6219 6368 char *pool;
6220 6369 zfs_mnted_t mnted;
6221 6370 char *mntpt;
6222 6371 char *sign;
6223 6372 const char *fcn = "find_zfs_existing()";
6224 6373
6225 6374 pool = get_pool(osdev);
6226 6375 INJECT_ERROR1("ZFS_FIND_EXIST_POOL", pool = NULL);
6227 6376 if (pool == NULL) {
6228 6377 bam_error(_("failed to get pool for device: %s\n"), osdev);
6229 6378 return (NULL);
6230 6379 }
6231 6380
6232 6381 mntpt = mount_top_dataset(pool, &mnted);
6233 6382 INJECT_ERROR1("ZFS_FIND_EXIST_MOUNT_TOP", mntpt = NULL);
6234 6383 if (mntpt == NULL) {
6235 6384 bam_error(_("failed to mount top dataset for pool: %s\n"),
6236 6385 pool);
6237 6386 free(pool);
6238 6387 return (NULL);
6239 6388 }
6240 6389
6241 6390 sign = find_primary_common(mntpt, "zfs");
6242 6391 if (sign == NULL) {
6243 6392 sign = find_backup_common(mntpt, "zfs");
6244 6393 BAM_DPRINTF(("%s: existing backup sign: %s\n", fcn,
6245 6394 sign ? sign : "NULL"));
6246 6395 } else {
6247 6396 BAM_DPRINTF(("%s: existing primary sign: %s\n", fcn, sign));
6248 6397 }
6249 6398
6250 6399 (void) umount_top_dataset(pool, mnted, mntpt);
6251 6400
6252 6401 free(pool);
6253 6402
6254 6403 return (sign);
6255 6404 }
6256 6405
6257 6406 static char *
6258 6407 find_existing_sign(char *osroot, char *osdev, char *fstype)
6259 6408 {
6260 6409 const char *fcn = "find_existing_sign()";
6261 6410
6262 6411 INJECT_ERROR1("FIND_EXIST_NOTSUP_FS", fstype = "foofs");
6263 6412 if (strcmp(fstype, "ufs") == 0) {
6264 6413 BAM_DPRINTF(("%s: checking for existing UFS sign\n", fcn));
6265 6414 return (find_ufs_existing(osroot));
6266 6415 } else if (strcmp(fstype, "zfs") == 0) {
6267 6416 BAM_DPRINTF(("%s: checking for existing ZFS sign\n", fcn));
6268 6417 return (find_zfs_existing(osdev));
6269 6418 } else {
6270 6419 bam_error(_("boot signature not supported for fstype: %s\n"),
6271 6420 fstype);
6272 6421 return (NULL);
6273 6422 }
6274 6423 }
6275 6424
6276 6425 #define MH_HASH_SZ 16
6277 6426
6278 6427 typedef enum {
6279 6428 MH_ERROR = -1,
6280 6429 MH_NOMATCH,
6281 6430 MH_MATCH
6282 6431 } mh_search_t;
6283 6432
6284 6433 typedef struct mcache {
6285 6434 char *mc_special;
6286 6435 char *mc_mntpt;
6287 6436 char *mc_fstype;
6288 6437 struct mcache *mc_next;
6289 6438 } mcache_t;
6290 6439
6291 6440 typedef struct mhash {
6292 6441 mcache_t *mh_hash[MH_HASH_SZ];
6293 6442 } mhash_t;
6294 6443
6295 6444 static int
6296 6445 mhash_fcn(char *key)
6297 6446 {
6298 6447 int i;
6299 6448 uint64_t sum = 0;
6300 6449
6301 6450 for (i = 0; key[i] != '\0'; i++) {
6302 6451 sum += (uchar_t)key[i];
6303 6452 }
6304 6453
6305 6454 sum %= MH_HASH_SZ;
6306 6455
6307 6456 assert(sum < MH_HASH_SZ);
6308 6457
6309 6458 return (sum);
6310 6459 }
6311 6460
6312 6461 static mhash_t *
6313 6462 cache_mnttab(void)
6314 6463 {
6315 6464 FILE *mfp;
6316 6465 struct extmnttab mnt;
6317 6466 mcache_t *mcp;
6318 6467 mhash_t *mhp;
6319 6468 char *ctds;
6320 6469 int idx;
6321 6470 int error;
6322 6471 char *special_dup;
6323 6472 const char *fcn = "cache_mnttab()";
6324 6473
6325 6474 mfp = fopen(MNTTAB, "r");
6326 6475 error = errno;
6327 6476 INJECT_ERROR1("CACHE_MNTTAB_MNTTAB_ERR", mfp = NULL);
6328 6477 if (mfp == NULL) {
6329 6478 bam_error(_("failed to open file: %s: %s\n"), MNTTAB,
6330 6479 strerror(error));
6331 6480 return (NULL);
6332 6481 }
6333 6482
6334 6483 mhp = s_calloc(1, sizeof (mhash_t));
6335 6484
6336 6485 resetmnttab(mfp);
6337 6486
6338 6487 while (getextmntent(mfp, &mnt, sizeof (mnt)) == 0) {
6339 6488 /* only cache ufs */
6340 6489 if (strcmp(mnt.mnt_fstype, "ufs") != 0)
6341 6490 continue;
6342 6491
6343 6492 /* basename() modifies its arg, so dup it */
6344 6493 special_dup = s_strdup(mnt.mnt_special);
6345 6494 ctds = basename(special_dup);
6346 6495
6347 6496 mcp = s_calloc(1, sizeof (mcache_t));
6348 6497 mcp->mc_special = s_strdup(ctds);
6349 6498 mcp->mc_mntpt = s_strdup(mnt.mnt_mountp);
6350 6499 mcp->mc_fstype = s_strdup(mnt.mnt_fstype);
6351 6500 BAM_DPRINTF(("%s: caching mount: special=%s, mntpt=%s, "
6352 6501 "fstype=%s\n", fcn, ctds, mnt.mnt_mountp, mnt.mnt_fstype));
6353 6502 idx = mhash_fcn(ctds);
6354 6503 mcp->mc_next = mhp->mh_hash[idx];
6355 6504 mhp->mh_hash[idx] = mcp;
6356 6505 free(special_dup);
6357 6506 }
6358 6507
6359 6508 (void) fclose(mfp);
6360 6509
6361 6510 return (mhp);
6362 6511 }
6363 6512
6364 6513 static void
6365 6514 free_mnttab(mhash_t *mhp)
6366 6515 {
6367 6516 mcache_t *mcp;
6368 6517 int i;
6369 6518
6370 6519 for (i = 0; i < MH_HASH_SZ; i++) {
6371 6520 while ((mcp = mhp->mh_hash[i]) != NULL) {
6372 6521 mhp->mh_hash[i] = mcp->mc_next;
6373 6522 free(mcp->mc_special);
6374 6523 free(mcp->mc_mntpt);
6375 6524 free(mcp->mc_fstype);
6376 6525 free(mcp);
6377 6526 }
6378 6527 }
6379 6528
6380 6529 for (i = 0; i < MH_HASH_SZ; i++) {
6381 6530 assert(mhp->mh_hash[i] == NULL);
6382 6531 }
6383 6532 free(mhp);
6384 6533 }
6385 6534
6386 6535 static mh_search_t
6387 6536 search_hash(mhash_t *mhp, char *special, char **mntpt)
6388 6537 {
6389 6538 int idx;
6390 6539 mcache_t *mcp;
6391 6540 const char *fcn = "search_hash()";
6392 6541
6393 6542 assert(mntpt);
6394 6543
6395 6544 *mntpt = NULL;
6396 6545
6397 6546 INJECT_ERROR1("SEARCH_HASH_FULL_PATH", special = "/foo");
6398 6547 if (strchr(special, '/')) {
6399 6548 bam_error(_("invalid key for mnttab hash: %s\n"), special);
6400 6549 return (MH_ERROR);
6401 6550 }
6402 6551
6403 6552 idx = mhash_fcn(special);
6404 6553
6405 6554 for (mcp = mhp->mh_hash[idx]; mcp; mcp = mcp->mc_next) {
6406 6555 if (strcmp(mcp->mc_special, special) == 0)
6407 6556 break;
6408 6557 }
6409 6558
6410 6559 if (mcp == NULL) {
6411 6560 BAM_DPRINTF(("%s: no match in cache for: %s\n", fcn, special));
6412 6561 return (MH_NOMATCH);
6413 6562 }
6414 6563
6415 6564 assert(strcmp(mcp->mc_fstype, "ufs") == 0);
6416 6565 *mntpt = mcp->mc_mntpt;
6417 6566 BAM_DPRINTF(("%s: *MATCH* in cache for: %s\n", fcn, special));
6418 6567 return (MH_MATCH);
6419 6568 }
6420 6569
6421 6570 static int
6422 6571 check_add_ufs_sign_to_list(FILE *tfp, char *mntpt)
6423 6572 {
6424 6573 char *sign;
6425 6574 char *signline;
6426 6575 char signbuf[MAXNAMELEN];
6427 6576 int len;
6428 6577 int error;
6429 6578 const char *fcn = "check_add_ufs_sign_to_list()";
6430 6579
6431 6580 /* safe to specify NULL as "osdev" arg for UFS */
6432 6581 sign = find_existing_sign(mntpt, NULL, "ufs");
6433 6582 if (sign == NULL) {
6434 6583 /* No existing signature, nothing to add to list */
6435 6584 BAM_DPRINTF(("%s: no sign on %s to add to signlist\n",
6436 6585 fcn, mntpt));
6437 6586 return (0);
6438 6587 }
6439 6588
6440 6589 (void) snprintf(signbuf, sizeof (signbuf), "%s\n", sign);
6441 6590 signline = signbuf;
6442 6591
6443 6592 INJECT_ERROR1("UFS_MNTPT_SIGN_NOTUFS", signline = "pool_rpool10\n");
6444 6593 if (strncmp(signline, GRUBSIGN_UFS_PREFIX,
6445 6594 strlen(GRUBSIGN_UFS_PREFIX))) {
6446 6595 bam_error(_("invalid UFS boot signature %s\n"), sign);
6447 6596 free(sign);
6448 6597 /* ignore invalid signatures */
6449 6598 return (0);
6450 6599 }
6451 6600
6452 6601 len = fputs(signline, tfp);
6453 6602 error = errno;
6454 6603 INJECT_ERROR1("SIGN_LIST_PUTS_ERROR", len = 0);
6455 6604 if (len != strlen(signline)) {
6456 6605 bam_error(_("failed to write signature %s to signature "
6457 6606 "list: %s\n"), sign, strerror(error));
6458 6607 free(sign);
6459 6608 return (-1);
6460 6609 }
6461 6610
6462 6611 free(sign);
6463 6612
6464 6613 BAM_DPRINTF(("%s: successfully added sign on %s to signlist\n",
6465 6614 fcn, mntpt));
6466 6615 return (0);
6467 6616 }
6468 6617
6469 6618 /*
6470 6619 * slice is a basename not a full pathname
6471 6620 */
6472 6621 static int
6473 6622 process_slice_common(char *slice, FILE *tfp, mhash_t *mhp, char *tmpmnt)
6474 6623 {
6475 6624 int ret;
6476 6625 char cmd[PATH_MAX];
6477 6626 char path[PATH_MAX];
6478 6627 struct stat sbuf;
6479 6628 char *mntpt;
6480 6629 filelist_t flist = {0};
6481 6630 char *fstype;
6482 6631 char blkslice[PATH_MAX];
6483 6632 const char *fcn = "process_slice_common()";
6484 6633
6485 6634
6486 6635 ret = search_hash(mhp, slice, &mntpt);
6487 6636 switch (ret) {
6488 6637 case MH_MATCH:
6489 6638 if (check_add_ufs_sign_to_list(tfp, mntpt) == -1)
6490 6639 return (-1);
6491 6640 else
6492 6641 return (0);
6493 6642 case MH_NOMATCH:
6494 6643 break;
6495 6644 case MH_ERROR:
6496 6645 default:
6497 6646 return (-1);
6498 6647 }
6499 6648
6500 6649 (void) snprintf(path, sizeof (path), "/dev/rdsk/%s", slice);
6501 6650 if (stat(path, &sbuf) == -1) {
6502 6651 BAM_DPRINTF(("%s: slice does not exist: %s\n", fcn, path));
6503 6652 return (0);
6504 6653 }
6505 6654
6506 6655 /* Check if ufs. Call ufs fstyp directly to avoid pcfs conflicts. */
6507 6656 (void) snprintf(cmd, sizeof (cmd),
6508 6657 "/usr/lib/fs/ufs/fstyp /dev/rdsk/%s 2>/dev/null",
6509 6658 slice);
6510 6659
6511 6660 if (exec_cmd(cmd, &flist) != 0) {
6512 6661 if (bam_verbose)
6513 6662 bam_print(_("fstyp failed for slice: %s\n"), slice);
6514 6663 return (0);
6515 6664 }
6516 6665
6517 6666 if ((flist.head == NULL) || (flist.head != flist.tail)) {
6518 6667 if (bam_verbose)
6519 6668 bam_print(_("bad output from fstyp for slice: %s\n"),
6520 6669 slice);
6521 6670 filelist_free(&flist);
6522 6671 return (0);
6523 6672 }
6524 6673
6525 6674 fstype = strtok(flist.head->line, " \t\n");
6526 6675 if (fstype == NULL || strcmp(fstype, "ufs") != 0) {
6527 6676 if (bam_verbose)
6528 6677 bam_print(_("%s is not a ufs slice: %s\n"),
6529 6678 slice, fstype);
6530 6679 filelist_free(&flist);
6531 6680 return (0);
6532 6681 }
6533 6682
6534 6683 filelist_free(&flist);
6535 6684
6536 6685 /*
6537 6686 * Since we are mounting the filesystem read-only, the
6538 6687 * the last mount field of the superblock is unchanged
6539 6688 * and does not need to be fixed up post-mount;
6540 6689 */
6541 6690
6542 6691 (void) snprintf(blkslice, sizeof (blkslice), "/dev/dsk/%s",
6543 6692 slice);
6544 6693
6545 6694 (void) snprintf(cmd, sizeof (cmd),
6546 6695 "/usr/sbin/mount -F ufs -o ro %s %s "
6547 6696 "> /dev/null 2>&1", blkslice, tmpmnt);
6548 6697
6549 6698 if (exec_cmd(cmd, NULL) != 0) {
6550 6699 if (bam_verbose)
6551 6700 bam_print(_("mount of %s (fstype %s) failed\n"),
6552 6701 blkslice, "ufs");
6553 6702 return (0);
6554 6703 }
6555 6704
6556 6705 ret = check_add_ufs_sign_to_list(tfp, tmpmnt);
6557 6706
6558 6707 (void) snprintf(cmd, sizeof (cmd),
6559 6708 "/usr/sbin/umount -f %s > /dev/null 2>&1",
6560 6709 tmpmnt);
6561 6710
6562 6711 if (exec_cmd(cmd, NULL) != 0) {
6563 6712 bam_print(_("umount of %s failed\n"), slice);
6564 6713 return (0);
6565 6714 }
6566 6715
6567 6716 return (ret);
6568 6717 }
6569 6718
6570 6719 static int
6571 6720 process_vtoc_slices(
6572 6721 char *s0,
6573 6722 struct vtoc *vtoc,
6574 6723 FILE *tfp,
6575 6724 mhash_t *mhp,
6576 6725 char *tmpmnt)
6577 6726 {
6578 6727 int idx;
6579 6728 char slice[PATH_MAX];
6580 6729 size_t len;
6581 6730 char *cp;
6582 6731 const char *fcn = "process_vtoc_slices()";
6583 6732
6584 6733 len = strlen(s0);
6585 6734
6586 6735 assert(s0[len - 2] == 's' && s0[len - 1] == '0');
6587 6736
6588 6737 s0[len - 1] = '\0';
6589 6738
6590 6739 (void) strlcpy(slice, s0, sizeof (slice));
6591 6740
6592 6741 s0[len - 1] = '0';
6593 6742
6594 6743 cp = slice + len - 1;
6595 6744
6596 6745 for (idx = 0; idx < vtoc->v_nparts; idx++) {
6597 6746
6598 6747 (void) snprintf(cp, sizeof (slice) - (len - 1), "%u", idx);
6599 6748
6600 6749 if (vtoc->v_part[idx].p_size == 0) {
6601 6750 BAM_DPRINTF(("%s: VTOC: skipping 0-length slice: %s\n",
6602 6751 fcn, slice));
6603 6752 continue;
6604 6753 }
6605 6754
6606 6755 /* Skip "SWAP", "USR", "BACKUP", "VAR", "HOME", "ALTSCTR" */
6607 6756 switch (vtoc->v_part[idx].p_tag) {
6608 6757 case V_SWAP:
6609 6758 case V_USR:
6610 6759 case V_BACKUP:
6611 6760 case V_VAR:
6612 6761 case V_HOME:
6613 6762 case V_ALTSCTR:
6614 6763 BAM_DPRINTF(("%s: VTOC: unsupported tag, "
6615 6764 "skipping: %s\n", fcn, slice));
6616 6765 continue;
6617 6766 default:
6618 6767 BAM_DPRINTF(("%s: VTOC: supported tag, checking: %s\n",
6619 6768 fcn, slice));
6620 6769 break;
6621 6770 }
6622 6771
6623 6772 /* skip unmountable and readonly slices */
6624 6773 switch (vtoc->v_part[idx].p_flag) {
6625 6774 case V_UNMNT:
6626 6775 case V_RONLY:
6627 6776 BAM_DPRINTF(("%s: VTOC: non-RDWR flag, skipping: %s\n",
6628 6777 fcn, slice));
6629 6778 continue;
6630 6779 default:
6631 6780 BAM_DPRINTF(("%s: VTOC: RDWR flag, checking: %s\n",
6632 6781 fcn, slice));
6633 6782 break;
6634 6783 }
6635 6784
6636 6785 if (process_slice_common(slice, tfp, mhp, tmpmnt) == -1) {
6637 6786 return (-1);
6638 6787 }
6639 6788 }
6640 6789
6641 6790 return (0);
6642 6791 }
6643 6792
6644 6793 static int
6645 6794 process_efi_slices(
6646 6795 char *s0,
6647 6796 struct dk_gpt *efi,
6648 6797 FILE *tfp,
6649 6798 mhash_t *mhp,
6650 6799 char *tmpmnt)
6651 6800 {
6652 6801 int idx;
6653 6802 char slice[PATH_MAX];
6654 6803 size_t len;
6655 6804 char *cp;
6656 6805 const char *fcn = "process_efi_slices()";
6657 6806
6658 6807 len = strlen(s0);
6659 6808
6660 6809 assert(s0[len - 2] == 's' && s0[len - 1] == '0');
6661 6810
6662 6811 s0[len - 1] = '\0';
6663 6812
6664 6813 (void) strlcpy(slice, s0, sizeof (slice));
6665 6814
6666 6815 s0[len - 1] = '0';
6667 6816
6668 6817 cp = slice + len - 1;
6669 6818
6670 6819 for (idx = 0; idx < efi->efi_nparts; idx++) {
6671 6820
6672 6821 (void) snprintf(cp, sizeof (slice) - (len - 1), "%u", idx);
6673 6822
6674 6823 if (efi->efi_parts[idx].p_size == 0) {
6675 6824 BAM_DPRINTF(("%s: EFI: skipping 0-length slice: %s\n",
6676 6825 fcn, slice));
6677 6826 continue;
6678 6827 }
6679 6828
6680 6829 /* Skip "SWAP", "USR", "BACKUP", "VAR", "HOME", "ALTSCTR" */
6681 6830 switch (efi->efi_parts[idx].p_tag) {
6682 6831 case V_SWAP:
6683 6832 case V_USR:
6684 6833 case V_BACKUP:
6685 6834 case V_VAR:
6686 6835 case V_HOME:
6687 6836 case V_ALTSCTR:
6688 6837 BAM_DPRINTF(("%s: EFI: unsupported tag, skipping: %s\n",
6689 6838 fcn, slice));
6690 6839 continue;
6691 6840 default:
6692 6841 BAM_DPRINTF(("%s: EFI: supported tag, checking: %s\n",
6693 6842 fcn, slice));
6694 6843 break;
6695 6844 }
6696 6845
6697 6846 /* skip unmountable and readonly slices */
6698 6847 switch (efi->efi_parts[idx].p_flag) {
6699 6848 case V_UNMNT:
6700 6849 case V_RONLY:
6701 6850 BAM_DPRINTF(("%s: EFI: non-RDWR flag, skipping: %s\n",
6702 6851 fcn, slice));
6703 6852 continue;
6704 6853 default:
6705 6854 BAM_DPRINTF(("%s: EFI: RDWR flag, checking: %s\n",
6706 6855 fcn, slice));
6707 6856 break;
6708 6857 }
6709 6858
6710 6859 if (process_slice_common(slice, tfp, mhp, tmpmnt) == -1) {
6711 6860 return (-1);
6712 6861 }
6713 6862 }
6714 6863
6715 6864 return (0);
6716 6865 }
6717 6866
6718 6867 /*
6719 6868 * s0 is a basename not a full path
6720 6869 */
6721 6870 static int
6722 6871 process_slice0(char *s0, FILE *tfp, mhash_t *mhp, char *tmpmnt)
6723 6872 {
6724 6873 struct vtoc vtoc;
6725 6874 struct dk_gpt *efi;
6726 6875 char s0path[PATH_MAX];
6727 6876 struct stat sbuf;
6728 6877 int e_flag;
6729 6878 int v_flag;
6730 6879 int retval;
6731 6880 int err;
6732 6881 int fd;
6733 6882 const char *fcn = "process_slice0()";
6734 6883
6735 6884 (void) snprintf(s0path, sizeof (s0path), "/dev/rdsk/%s", s0);
6736 6885
6737 6886 if (stat(s0path, &sbuf) == -1) {
6738 6887 BAM_DPRINTF(("%s: slice 0 does not exist: %s\n", fcn, s0path));
6739 6888 return (0);
6740 6889 }
6741 6890
6742 6891 fd = open(s0path, O_NONBLOCK|O_RDONLY);
6743 6892 if (fd == -1) {
6744 6893 bam_error(_("failed to open file: %s: %s\n"), s0path,
6745 6894 strerror(errno));
6746 6895 return (0);
6747 6896 }
6748 6897
6749 6898 e_flag = v_flag = 0;
6750 6899 retval = ((err = read_vtoc(fd, &vtoc)) >= 0) ? 0 : err;
6751 6900 switch (retval) {
6752 6901 case VT_EIO:
6753 6902 BAM_DPRINTF(("%s: VTOC: failed to read: %s\n",
6754 6903 fcn, s0path));
6755 6904 break;
6756 6905 case VT_EINVAL:
6757 6906 BAM_DPRINTF(("%s: VTOC: is INVALID: %s\n",
6758 6907 fcn, s0path));
6759 6908 break;
6760 6909 case VT_ERROR:
6761 6910 BAM_DPRINTF(("%s: VTOC: unknown error while "
6762 6911 "reading: %s\n", fcn, s0path));
6763 6912 break;
6764 6913 case VT_ENOTSUP:
6765 6914 e_flag = 1;
6766 6915 BAM_DPRINTF(("%s: VTOC: not supported: %s\n",
6767 6916 fcn, s0path));
6768 6917 break;
6769 6918 case 0:
6770 6919 v_flag = 1;
6771 6920 BAM_DPRINTF(("%s: VTOC: SUCCESS reading: %s\n",
6772 6921 fcn, s0path));
6773 6922 break;
6774 6923 default:
6775 6924 BAM_DPRINTF(("%s: VTOC: READ: unknown return "
6776 6925 "code: %s\n", fcn, s0path));
6777 6926 break;
6778 6927 }
6779 6928
6780 6929
6781 6930 if (e_flag) {
6782 6931 e_flag = 0;
6783 6932 retval = ((err = efi_alloc_and_read(fd, &efi)) >= 0) ? 0 : err;
6784 6933 switch (retval) {
6785 6934 case VT_EIO:
6786 6935 BAM_DPRINTF(("%s: EFI: failed to read: %s\n",
6787 6936 fcn, s0path));
6788 6937 break;
6789 6938 case VT_EINVAL:
6790 6939 BAM_DPRINTF(("%s: EFI: is INVALID: %s\n", fcn, s0path));
6791 6940 break;
6792 6941 case VT_ERROR:
6793 6942 BAM_DPRINTF(("%s: EFI: unknown error while "
6794 6943 "reading: %s\n", fcn, s0path));
6795 6944 break;
6796 6945 case VT_ENOTSUP:
6797 6946 BAM_DPRINTF(("%s: EFI: not supported: %s\n",
6798 6947 fcn, s0path));
6799 6948 break;
6800 6949 case 0:
6801 6950 e_flag = 1;
6802 6951 BAM_DPRINTF(("%s: EFI: SUCCESS reading: %s\n",
6803 6952 fcn, s0path));
6804 6953 break;
6805 6954 default:
6806 6955 BAM_DPRINTF(("%s: EFI: READ: unknown return code: %s\n",
6807 6956 fcn, s0path));
6808 6957 break;
6809 6958 }
6810 6959 }
6811 6960
6812 6961 (void) close(fd);
6813 6962
6814 6963 if (v_flag) {
6815 6964 retval = process_vtoc_slices(s0,
6816 6965 &vtoc, tfp, mhp, tmpmnt);
6817 6966 } else if (e_flag) {
6818 6967 retval = process_efi_slices(s0,
6819 6968 efi, tfp, mhp, tmpmnt);
6820 6969 } else {
6821 6970 BAM_DPRINTF(("%s: disk has neither VTOC nor EFI: %s\n",
6822 6971 fcn, s0path));
6823 6972 return (0);
6824 6973 }
6825 6974
6826 6975 return (retval);
6827 6976 }
6828 6977
6829 6978 /*
6830 6979 * Find and create a list of all existing UFS boot signatures
6831 6980 */
6832 6981 static int
6833 6982 FindAllUfsSignatures(void)
6834 6983 {
6835 6984 mhash_t *mnttab_hash;
6836 6985 DIR *dirp = NULL;
6837 6986 struct dirent *dp;
6838 6987 char tmpmnt[PATH_MAX];
6839 6988 char cmd[PATH_MAX];
6840 6989 struct stat sb;
6841 6990 int fd;
6842 6991 FILE *tfp;
6843 6992 size_t len;
6844 6993 int ret;
6845 6994 int error;
6846 6995 const char *fcn = "FindAllUfsSignatures()";
6847 6996
6848 6997 if (stat(UFS_SIGNATURE_LIST, &sb) != -1) {
6849 6998 bam_print(_(" - signature list %s exists\n"),
6850 6999 UFS_SIGNATURE_LIST);
6851 7000 return (0);
6852 7001 }
6853 7002
6854 7003 fd = open(UFS_SIGNATURE_LIST".tmp",
6855 7004 O_RDWR|O_CREAT|O_TRUNC, 0644);
6856 7005 error = errno;
6857 7006 INJECT_ERROR1("SIGN_LIST_TMP_TRUNC", fd = -1);
6858 7007 if (fd == -1) {
6859 7008 bam_error(_("failed to open file: %s: %s\n"),
6860 7009 UFS_SIGNATURE_LIST".tmp", strerror(error));
6861 7010 return (-1);
6862 7011 }
6863 7012
6864 7013 ret = close(fd);
6865 7014 error = errno;
6866 7015 INJECT_ERROR1("SIGN_LIST_TMP_CLOSE", ret = -1);
6867 7016 if (ret == -1) {
6868 7017 bam_error(_("failed to close file: %s: %s\n"),
6869 7018 UFS_SIGNATURE_LIST".tmp", strerror(error));
6870 7019 (void) unlink(UFS_SIGNATURE_LIST".tmp");
6871 7020 return (-1);
6872 7021 }
6873 7022
6874 7023 tfp = fopen(UFS_SIGNATURE_LIST".tmp", "a");
6875 7024 error = errno;
6876 7025 INJECT_ERROR1("SIGN_LIST_APPEND_FOPEN", tfp = NULL);
6877 7026 if (tfp == NULL) {
6878 7027 bam_error(_("failed to open file: %s: %s\n"),
6879 7028 UFS_SIGNATURE_LIST".tmp", strerror(error));
6880 7029 (void) unlink(UFS_SIGNATURE_LIST".tmp");
6881 7030 return (-1);
6882 7031 }
6883 7032
6884 7033 mnttab_hash = cache_mnttab();
6885 7034 INJECT_ERROR1("CACHE_MNTTAB_ERROR", mnttab_hash = NULL);
6886 7035 if (mnttab_hash == NULL) {
6887 7036 (void) fclose(tfp);
6888 7037 (void) unlink(UFS_SIGNATURE_LIST".tmp");
6889 7038 bam_error(_("%s: failed to cache /etc/mnttab\n"), fcn);
6890 7039 return (-1);
6891 7040 }
6892 7041
6893 7042 (void) snprintf(tmpmnt, sizeof (tmpmnt),
6894 7043 "/tmp/bootadm_ufs_sign_mnt.%d", getpid());
6895 7044 (void) unlink(tmpmnt);
6896 7045
6897 7046 ret = mkdirp(tmpmnt, DIR_PERMS);
6898 7047 error = errno;
6899 7048 INJECT_ERROR1("MKDIRP_SIGN_MNT", ret = -1);
6900 7049 if (ret == -1) {
6901 7050 bam_error(_("mkdir of %s failed: %s\n"), tmpmnt,
6902 7051 strerror(error));
6903 7052 free_mnttab(mnttab_hash);
6904 7053 (void) fclose(tfp);
6905 7054 (void) unlink(UFS_SIGNATURE_LIST".tmp");
6906 7055 return (-1);
6907 7056 }
6908 7057
6909 7058 dirp = opendir("/dev/rdsk");
6910 7059 error = errno;
6911 7060 INJECT_ERROR1("OPENDIR_DEV_RDSK", dirp = NULL);
6912 7061 if (dirp == NULL) {
6913 7062 bam_error(_("opendir of %s failed: %s\n"), "/dev/rdsk",
6914 7063 strerror(error));
6915 7064 goto fail;
6916 7065 }
6917 7066
6918 7067 while ((dp = readdir(dirp)) != NULL) {
6919 7068 if (strcmp(dp->d_name, ".") == 0 ||
6920 7069 strcmp(dp->d_name, "..") == 0)
6921 7070 continue;
6922 7071
6923 7072 /*
6924 7073 * we only look for the s0 slice. This is guranteed to
6925 7074 * have 's' at len - 2.
6926 7075 */
6927 7076 len = strlen(dp->d_name);
6928 7077 if (dp->d_name[len - 2 ] != 's' || dp->d_name[len - 1] != '0') {
6929 7078 BAM_DPRINTF(("%s: skipping non-s0 slice: %s\n",
6930 7079 fcn, dp->d_name));
6931 7080 continue;
6932 7081 }
6933 7082
6934 7083 ret = process_slice0(dp->d_name, tfp, mnttab_hash, tmpmnt);
6935 7084 INJECT_ERROR1("PROCESS_S0_FAIL", ret = -1);
6936 7085 if (ret == -1)
6937 7086 goto fail;
6938 7087 }
6939 7088
6940 7089 (void) closedir(dirp);
6941 7090 free_mnttab(mnttab_hash);
6942 7091 (void) rmdir(tmpmnt);
6943 7092
6944 7093 ret = fclose(tfp);
6945 7094 error = errno;
6946 7095 INJECT_ERROR1("FCLOSE_SIGNLIST_TMP", ret = EOF);
6947 7096 if (ret == EOF) {
6948 7097 bam_error(_("failed to close file: %s: %s\n"),
6949 7098 UFS_SIGNATURE_LIST".tmp", strerror(error));
6950 7099 (void) unlink(UFS_SIGNATURE_LIST".tmp");
6951 7100 return (-1);
6952 7101 }
6953 7102
6954 7103 /* We have a list of existing GRUB signatures. Sort it first */
6955 7104 (void) snprintf(cmd, sizeof (cmd),
6956 7105 "/usr/bin/sort -u %s.tmp > %s.sorted",
6957 7106 UFS_SIGNATURE_LIST, UFS_SIGNATURE_LIST);
6958 7107
6959 7108 ret = exec_cmd(cmd, NULL);
6960 7109 INJECT_ERROR1("SORT_SIGN_LIST", ret = 1);
6961 7110 if (ret != 0) {
6962 7111 bam_error(_("error sorting GRUB UFS boot signatures\n"));
6963 7112 (void) unlink(UFS_SIGNATURE_LIST".sorted");
6964 7113 (void) unlink(UFS_SIGNATURE_LIST".tmp");
6965 7114 return (-1);
6966 7115 }
6967 7116
6968 7117 (void) unlink(UFS_SIGNATURE_LIST".tmp");
6969 7118
6970 7119 ret = rename(UFS_SIGNATURE_LIST".sorted", UFS_SIGNATURE_LIST);
6971 7120 error = errno;
6972 7121 INJECT_ERROR1("RENAME_TMP_SIGNLIST", ret = -1);
6973 7122 if (ret == -1) {
6974 7123 bam_error(_("rename to file failed: %s: %s\n"),
6975 7124 UFS_SIGNATURE_LIST, strerror(error));
6976 7125 (void) unlink(UFS_SIGNATURE_LIST".sorted");
6977 7126 return (-1);
6978 7127 }
6979 7128
6980 7129 if (stat(UFS_SIGNATURE_LIST, &sb) == 0 && sb.st_size == 0) {
6981 7130 BAM_DPRINTF(("%s: generated zero length signlist: %s.\n",
6982 7131 fcn, UFS_SIGNATURE_LIST));
6983 7132 }
6984 7133
6985 7134 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
6986 7135 return (0);
6987 7136
6988 7137 fail:
6989 7138 if (dirp)
6990 7139 (void) closedir(dirp);
6991 7140 free_mnttab(mnttab_hash);
6992 7141 (void) rmdir(tmpmnt);
6993 7142 (void) fclose(tfp);
6994 7143 (void) unlink(UFS_SIGNATURE_LIST".tmp");
6995 7144 BAM_DPRINTF(("%s: returning FAILURE\n", fcn));
6996 7145 return (-1);
6997 7146 }
6998 7147
6999 7148 static char *
7000 7149 create_ufs_sign(void)
7001 7150 {
7002 7151 struct stat sb;
7003 7152 int signnum = -1;
7004 7153 char tmpsign[MAXNAMELEN + 1];
7005 7154 char *numstr;
7006 7155 int i;
7007 7156 FILE *tfp;
7008 7157 int ret;
7009 7158 int error;
7010 7159 const char *fcn = "create_ufs_sign()";
7011 7160
7012 7161 bam_print(_(" - searching for UFS boot signatures\n"));
7013 7162
7014 7163 ret = FindAllUfsSignatures();
7015 7164 INJECT_ERROR1("FIND_ALL_UFS", ret = -1);
7016 7165 if (ret == -1) {
7017 7166 bam_error(_("search for UFS boot signatures failed\n"));
7018 7167 return (NULL);
7019 7168 }
7020 7169
7021 7170 /* Make sure the list exists and is owned by root */
7022 7171 INJECT_ERROR1("SIGNLIST_NOT_CREATED",
7023 7172 (void) unlink(UFS_SIGNATURE_LIST));
7024 7173 if (stat(UFS_SIGNATURE_LIST, &sb) == -1 || sb.st_uid != 0) {
7025 7174 (void) unlink(UFS_SIGNATURE_LIST);
7026 7175 bam_error(_("missing UFS signature list file: %s\n"),
7027 7176 UFS_SIGNATURE_LIST);
7028 7177 return (NULL);
7029 7178 }
7030 7179
7031 7180 if (sb.st_size == 0) {
7032 7181 bam_print(_(" - no existing UFS boot signatures\n"));
7033 7182 i = 0;
7034 7183 goto found;
7035 7184 }
7036 7185
7037 7186 /* The signature list was sorted when it was created */
7038 7187 tfp = fopen(UFS_SIGNATURE_LIST, "r");
7039 7188 error = errno;
7040 7189 INJECT_ERROR1("FOPEN_SIGN_LIST", tfp = NULL);
7041 7190 if (tfp == NULL) {
7042 7191 bam_error(_("error opening UFS boot signature list "
7043 7192 "file %s: %s\n"), UFS_SIGNATURE_LIST, strerror(error));
7044 7193 (void) unlink(UFS_SIGNATURE_LIST);
7045 7194 return (NULL);
7046 7195 }
7047 7196
7048 7197 for (i = 0; s_fgets(tmpsign, sizeof (tmpsign), tfp); i++) {
7049 7198
7050 7199 if (strncmp(tmpsign, GRUBSIGN_UFS_PREFIX,
7051 7200 strlen(GRUBSIGN_UFS_PREFIX)) != 0) {
7052 7201 (void) fclose(tfp);
7053 7202 (void) unlink(UFS_SIGNATURE_LIST);
7054 7203 bam_error(_("bad UFS boot signature: %s\n"), tmpsign);
7055 7204 return (NULL);
7056 7205 }
7057 7206 numstr = tmpsign + strlen(GRUBSIGN_UFS_PREFIX);
7058 7207
7059 7208 if (numstr[0] == '\0' || !isdigit(numstr[0])) {
7060 7209 (void) fclose(tfp);
7061 7210 (void) unlink(UFS_SIGNATURE_LIST);
7062 7211 bam_error(_("bad UFS boot signature: %s\n"), tmpsign);
7063 7212 return (NULL);
7064 7213 }
7065 7214
7066 7215 signnum = atoi(numstr);
7067 7216 INJECT_ERROR1("NEGATIVE_SIGN", signnum = -1);
7068 7217 if (signnum < 0) {
7069 7218 (void) fclose(tfp);
7070 7219 (void) unlink(UFS_SIGNATURE_LIST);
7071 7220 bam_error(_("bad UFS boot signature: %s\n"), tmpsign);
7072 7221 return (NULL);
7073 7222 }
7074 7223
7075 7224 if (i != signnum) {
7076 7225 BAM_DPRINTF(("%s: found hole %d in sign list.\n",
7077 7226 fcn, i));
7078 7227 break;
7079 7228 }
7080 7229 }
7081 7230
7082 7231 (void) fclose(tfp);
7083 7232
7084 7233 found:
7085 7234 (void) snprintf(tmpsign, sizeof (tmpsign), "rootfs%d", i);
7086 7235
7087 7236 /* add the ufs signature to the /var/run list of signatures */
7088 7237 ret = ufs_add_to_sign_list(tmpsign);
7089 7238 INJECT_ERROR1("UFS_ADD_TO_SIGN_LIST", ret = -1);
7090 7239 if (ret == -1) {
7091 7240 (void) unlink(UFS_SIGNATURE_LIST);
7092 7241 bam_error(_("failed to add sign %s to signlist.\n"), tmpsign);
7093 7242 return (NULL);
7094 7243 }
7095 7244
7096 7245 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
7097 7246
7098 7247 return (s_strdup(tmpsign));
7099 7248 }
7100 7249
7101 7250 static char *
7102 7251 get_fstype(char *osroot)
7103 7252 {
7104 7253 FILE *mntfp;
7105 7254 struct mnttab mp = {0};
7106 7255 struct mnttab mpref = {0};
7107 7256 int error;
7108 7257 int ret;
7109 7258 const char *fcn = "get_fstype()";
7110 7259
7111 7260 INJECT_ERROR1("GET_FSTYPE_OSROOT", osroot = NULL);
7112 7261 if (osroot == NULL) {
7113 7262 bam_error(_("no OS mountpoint. Cannot determine fstype\n"));
7114 7263 return (NULL);
7115 7264 }
7116 7265
7117 7266 mntfp = fopen(MNTTAB, "r");
7118 7267 error = errno;
7119 7268 INJECT_ERROR1("GET_FSTYPE_FOPEN", mntfp = NULL);
7120 7269 if (mntfp == NULL) {
7121 7270 bam_error(_("failed to open file: %s: %s\n"), MNTTAB,
7122 7271 strerror(error));
7123 7272 return (NULL);
7124 7273 }
7125 7274
7126 7275 if (*osroot == '\0')
7127 7276 mpref.mnt_mountp = "/";
7128 7277 else
7129 7278 mpref.mnt_mountp = osroot;
7130 7279
7131 7280 ret = getmntany(mntfp, &mp, &mpref);
7132 7281 INJECT_ERROR1("GET_FSTYPE_GETMNTANY", ret = 1);
7133 7282 if (ret != 0) {
7134 7283 bam_error(_("failed to find OS mountpoint %s in %s\n"),
7135 7284 osroot, MNTTAB);
7136 7285 (void) fclose(mntfp);
7137 7286 return (NULL);
7138 7287 }
7139 7288 (void) fclose(mntfp);
7140 7289
7141 7290 INJECT_ERROR1("GET_FSTYPE_NULL", mp.mnt_fstype = NULL);
7142 7291 if (mp.mnt_fstype == NULL) {
7143 7292 bam_error(_("NULL fstype found for OS root %s\n"), osroot);
7144 7293 return (NULL);
7145 7294 }
7146 7295
7147 7296 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
7148 7297
7149 7298 return (s_strdup(mp.mnt_fstype));
7150 7299 }
7151 7300
7152 7301 static char *
7153 7302 create_zfs_sign(char *osdev)
7154 7303 {
7155 7304 char tmpsign[PATH_MAX];
7156 7305 char *pool;
7157 7306 const char *fcn = "create_zfs_sign()";
7158 7307
7159 7308 BAM_DPRINTF(("%s: entered. arg: %s\n", fcn, osdev));
7160 7309
7161 7310 /*
7162 7311 * First find the pool name
7163 7312 */
7164 7313 pool = get_pool(osdev);
7165 7314 INJECT_ERROR1("CREATE_ZFS_SIGN_GET_POOL", pool = NULL);
7166 7315 if (pool == NULL) {
7167 7316 bam_error(_("failed to get pool name from %s\n"), osdev);
7168 7317 return (NULL);
7169 7318 }
7170 7319
7171 7320 (void) snprintf(tmpsign, sizeof (tmpsign), "pool_%s", pool);
7172 7321
7173 7322 BAM_DPRINTF(("%s: created ZFS sign: %s\n", fcn, tmpsign));
7174 7323
7175 7324 free(pool);
7176 7325
7177 7326 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
7178 7327
7179 7328 return (s_strdup(tmpsign));
7180 7329 }
7181 7330
7182 7331 static char *
7183 7332 create_new_sign(char *osdev, char *fstype)
7184 7333 {
7185 7334 char *sign;
7186 7335 const char *fcn = "create_new_sign()";
7187 7336
7188 7337 INJECT_ERROR1("NEW_SIGN_FSTYPE", fstype = "foofs");
7189 7338
7190 7339 if (strcmp(fstype, "zfs") == 0) {
7191 7340 BAM_DPRINTF(("%s: created new ZFS sign\n", fcn));
7192 7341 sign = create_zfs_sign(osdev);
7193 7342 } else if (strcmp(fstype, "ufs") == 0) {
7194 7343 BAM_DPRINTF(("%s: created new UFS sign\n", fcn));
7195 7344 sign = create_ufs_sign();
7196 7345 } else {
7197 7346 bam_error(_("boot signature not supported for fstype: %s\n"),
7198 7347 fstype);
7199 7348 sign = NULL;
7200 7349 }
7201 7350
7202 7351 BAM_DPRINTF(("%s: created new sign: %s\n", fcn,
7203 7352 sign ? sign : "<NULL>"));
7204 7353 return (sign);
7205 7354 }
7206 7355
7207 7356 static int
7208 7357 set_backup_common(char *mntpt, char *sign)
7209 7358 {
7210 7359 FILE *bfp;
7211 7360 char backup[PATH_MAX];
7212 7361 char tmpsign[PATH_MAX];
7213 7362 int error;
7214 7363 char *bdir;
7215 7364 char *backup_dup;
7216 7365 struct stat sb;
7217 7366 int ret;
7218 7367 const char *fcn = "set_backup_common()";
7219 7368
7220 7369 (void) snprintf(backup, sizeof (backup), "%s%s",
7221 7370 mntpt, GRUBSIGN_BACKUP);
7222 7371
7223 7372 /* First read the backup */
7224 7373 bfp = fopen(backup, "r");
7225 7374 if (bfp != NULL) {
7226 7375 while (s_fgets(tmpsign, sizeof (tmpsign), bfp)) {
7227 7376 if (strcmp(tmpsign, sign) == 0) {
7228 7377 BAM_DPRINTF(("%s: found sign (%s) in backup.\n",
7229 7378 fcn, sign));
7230 7379 (void) fclose(bfp);
7231 7380 return (0);
7232 7381 }
7233 7382 }
7234 7383 (void) fclose(bfp);
7235 7384 BAM_DPRINTF(("%s: backup exists but sign %s not found\n",
7236 7385 fcn, sign));
7237 7386 } else {
7238 7387 BAM_DPRINTF(("%s: no backup file (%s) found.\n", fcn, backup));
7239 7388 }
7240 7389
7241 7390 /*
7242 7391 * Didn't find the correct signature. First create
7243 7392 * the directory if necessary.
7244 7393 */
7245 7394
7246 7395 /* dirname() modifies its argument so dup it */
7247 7396 backup_dup = s_strdup(backup);
7248 7397 bdir = dirname(backup_dup);
7249 7398 assert(bdir);
7250 7399
7251 7400 ret = stat(bdir, &sb);
7252 7401 INJECT_ERROR1("SET_BACKUP_STAT", ret = -1);
7253 7402 if (ret == -1) {
7254 7403 BAM_DPRINTF(("%s: backup dir (%s) does not exist.\n",
7255 7404 fcn, bdir));
7256 7405 ret = mkdirp(bdir, DIR_PERMS);
7257 7406 error = errno;
7258 7407 INJECT_ERROR1("SET_BACKUP_MKDIRP", ret = -1);
7259 7408 if (ret == -1) {
7260 7409 bam_error(_("mkdirp() of backup dir failed: %s: %s\n"),
7261 7410 GRUBSIGN_BACKUP, strerror(error));
7262 7411 free(backup_dup);
7263 7412 return (-1);
7264 7413 }
7265 7414 }
7266 7415 free(backup_dup);
7267 7416
7268 7417 /*
7269 7418 * Open the backup in append mode to add the correct
7270 7419 * signature;
7271 7420 */
7272 7421 bfp = fopen(backup, "a");
7273 7422 error = errno;
7274 7423 INJECT_ERROR1("SET_BACKUP_FOPEN_A", bfp = NULL);
7275 7424 if (bfp == NULL) {
7276 7425 bam_error(_("error opening boot signature backup "
7277 7426 "file %s: %s\n"), GRUBSIGN_BACKUP, strerror(error));
7278 7427 return (-1);
7279 7428 }
7280 7429
7281 7430 (void) snprintf(tmpsign, sizeof (tmpsign), "%s\n", sign);
7282 7431
7283 7432 ret = fputs(tmpsign, bfp);
7284 7433 error = errno;
7285 7434 INJECT_ERROR1("SET_BACKUP_FPUTS", ret = 0);
7286 7435 if (ret != strlen(tmpsign)) {
7287 7436 bam_error(_("error writing boot signature backup "
7288 7437 "file %s: %s\n"), GRUBSIGN_BACKUP, strerror(error));
7289 7438 (void) fclose(bfp);
7290 7439 return (-1);
7291 7440 }
7292 7441
7293 7442 (void) fclose(bfp);
7294 7443
7295 7444 if (bam_verbose)
7296 7445 bam_print(_("updated boot signature backup file %s\n"),
7297 7446 GRUBSIGN_BACKUP);
7298 7447
7299 7448 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
7300 7449
7301 7450 return (0);
7302 7451 }
7303 7452
7304 7453 static int
7305 7454 set_backup_ufs(char *osroot, char *sign)
7306 7455 {
7307 7456 const char *fcn = "set_backup_ufs()";
7308 7457
7309 7458 BAM_DPRINTF(("%s: entered. args: %s %s\n", fcn, osroot, sign));
7310 7459 return (set_backup_common(osroot, sign));
7311 7460 }
7312 7461
7313 7462 static int
7314 7463 set_backup_zfs(char *osdev, char *sign)
7315 7464 {
7316 7465 char *pool;
7317 7466 char *mntpt;
7318 7467 zfs_mnted_t mnted;
7319 7468 int ret;
7320 7469 const char *fcn = "set_backup_zfs()";
7321 7470
7322 7471 BAM_DPRINTF(("%s: entered. args: %s %s\n", fcn, osdev, sign));
7323 7472
7324 7473 pool = get_pool(osdev);
7325 7474 INJECT_ERROR1("SET_BACKUP_GET_POOL", pool = NULL);
7326 7475 if (pool == NULL) {
7327 7476 bam_error(_("failed to get pool name from %s\n"), osdev);
7328 7477 return (-1);
7329 7478 }
7330 7479
7331 7480 mntpt = mount_top_dataset(pool, &mnted);
7332 7481 INJECT_ERROR1("SET_BACKUP_MOUNT_DATASET", mntpt = NULL);
7333 7482 if (mntpt == NULL) {
7334 7483 bam_error(_("failed to mount top dataset for %s\n"), pool);
7335 7484 free(pool);
7336 7485 return (-1);
7337 7486 }
7338 7487
7339 7488 ret = set_backup_common(mntpt, sign);
7340 7489
7341 7490 (void) umount_top_dataset(pool, mnted, mntpt);
7342 7491
7343 7492 free(pool);
7344 7493
7345 7494 INJECT_ERROR1("SET_BACKUP_ZFS_FAIL", ret = 1);
7346 7495 if (ret == 0) {
7347 7496 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
7348 7497 } else {
7349 7498 BAM_DPRINTF(("%s: returning FAILURE\n", fcn));
7350 7499 }
7351 7500
7352 7501 return (ret);
7353 7502 }
7354 7503
7355 7504 static int
7356 7505 set_backup(char *osroot, char *osdev, char *sign, char *fstype)
7357 7506 {
7358 7507 const char *fcn = "set_backup()";
7359 7508 int ret;
7360 7509
7361 7510 INJECT_ERROR1("SET_BACKUP_FSTYPE", fstype = "foofs");
7362 7511
7363 7512 if (strcmp(fstype, "ufs") == 0) {
7364 7513 BAM_DPRINTF(("%s: setting UFS backup sign\n", fcn));
7365 7514 ret = set_backup_ufs(osroot, sign);
7366 7515 } else if (strcmp(fstype, "zfs") == 0) {
7367 7516 BAM_DPRINTF(("%s: setting ZFS backup sign\n", fcn));
7368 7517 ret = set_backup_zfs(osdev, sign);
7369 7518 } else {
7370 7519 bam_error(_("boot signature not supported for fstype: %s\n"),
7371 7520 fstype);
7372 7521 ret = -1;
7373 7522 }
7374 7523
7375 7524 if (ret == 0) {
7376 7525 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
7377 7526 } else {
7378 7527 BAM_DPRINTF(("%s: returning FAILURE\n", fcn));
7379 7528 }
7380 7529
7381 7530 return (ret);
7382 7531 }
7383 7532
7384 7533 static int
7385 7534 set_primary_common(char *mntpt, char *sign)
7386 7535 {
7387 7536 char signfile[PATH_MAX];
7388 7537 char signdir[PATH_MAX];
7389 7538 struct stat sb;
7390 7539 int fd;
7391 7540 int error;
7392 7541 int ret;
7393 7542 const char *fcn = "set_primary_common()";
7394 7543
7395 7544 (void) snprintf(signfile, sizeof (signfile), "%s/%s/%s",
7396 7545 mntpt, GRUBSIGN_DIR, sign);
7397 7546
7398 7547 if (stat(signfile, &sb) != -1) {
7399 7548 if (bam_verbose)
7400 7549 bam_print(_("primary sign %s exists\n"), sign);
7401 7550 return (0);
7402 7551 } else {
7403 7552 BAM_DPRINTF(("%s: primary sign (%s) does not exist\n",
7404 7553 fcn, signfile));
7405 7554 }
7406 7555
7407 7556 (void) snprintf(signdir, sizeof (signdir), "%s/%s",
7408 7557 mntpt, GRUBSIGN_DIR);
7409 7558
7410 7559 if (stat(signdir, &sb) == -1) {
7411 7560 BAM_DPRINTF(("%s: primary signdir (%s) does not exist\n",
7412 7561 fcn, signdir));
7413 7562 ret = mkdirp(signdir, DIR_PERMS);
7414 7563 error = errno;
7415 7564 INJECT_ERROR1("SET_PRIMARY_MKDIRP", ret = -1);
7416 7565 if (ret == -1) {
7417 7566 bam_error(_("error creating boot signature "
7418 7567 "directory %s: %s\n"), signdir, strerror(errno));
7419 7568 return (-1);
7420 7569 }
7421 7570 }
7422 7571
7423 7572 fd = open(signfile, O_RDWR|O_CREAT|O_TRUNC, 0444);
7424 7573 error = errno;
7425 7574 INJECT_ERROR1("PRIMARY_SIGN_CREAT", fd = -1);
7426 7575 if (fd == -1) {
7427 7576 bam_error(_("error creating primary boot signature %s: %s\n"),
7428 7577 signfile, strerror(error));
7429 7578 return (-1);
7430 7579 }
7431 7580
7432 7581 ret = fsync(fd);
7433 7582 error = errno;
7434 7583 INJECT_ERROR1("PRIMARY_FSYNC", ret = -1);
7435 7584 if (ret != 0) {
7436 7585 bam_error(_("error syncing primary boot signature %s: %s\n"),
7437 7586 signfile, strerror(error));
7438 7587 }
7439 7588
7440 7589 (void) close(fd);
7441 7590
7442 7591 if (bam_verbose)
7443 7592 bam_print(_("created primary GRUB boot signature: %s\n"),
7444 7593 signfile);
7445 7594
7446 7595 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
7447 7596
7448 7597 return (0);
7449 7598 }
7450 7599
7451 7600 static int
7452 7601 set_primary_ufs(char *osroot, char *sign)
7453 7602 {
7454 7603 const char *fcn = "set_primary_ufs()";
7455 7604
7456 7605 BAM_DPRINTF(("%s: entered. args: %s %s\n", fcn, osroot, sign));
7457 7606 return (set_primary_common(osroot, sign));
7458 7607 }
7459 7608
7460 7609 static int
7461 7610 set_primary_zfs(char *osdev, char *sign)
7462 7611 {
7463 7612 char *pool;
7464 7613 char *mntpt;
7465 7614 zfs_mnted_t mnted;
7466 7615 int ret;
7467 7616 const char *fcn = "set_primary_zfs()";
7468 7617
7469 7618 BAM_DPRINTF(("%s: entered. args: %s %s\n", fcn, osdev, sign));
7470 7619
7471 7620 pool = get_pool(osdev);
7472 7621 INJECT_ERROR1("SET_PRIMARY_ZFS_GET_POOL", pool = NULL);
7473 7622 if (pool == NULL) {
7474 7623 bam_error(_("failed to get pool name from %s\n"), osdev);
7475 7624 return (-1);
7476 7625 }
7477 7626
7478 7627 /* Pool name must exist in the sign */
7479 7628 ret = (strstr(sign, pool) != NULL);
7480 7629 INJECT_ERROR1("SET_PRIMARY_ZFS_POOL_SIGN_INCOMPAT", ret = 0);
7481 7630 if (ret == 0) {
7482 7631 bam_error(_("pool name %s not present in signature %s\n"),
7483 7632 pool, sign);
7484 7633 free(pool);
7485 7634 return (-1);
7486 7635 }
7487 7636
7488 7637 mntpt = mount_top_dataset(pool, &mnted);
7489 7638 INJECT_ERROR1("SET_PRIMARY_ZFS_MOUNT_DATASET", mntpt = NULL);
7490 7639 if (mntpt == NULL) {
7491 7640 bam_error(_("failed to mount top dataset for %s\n"), pool);
7492 7641 free(pool);
7493 7642 return (-1);
7494 7643 }
7495 7644
7496 7645 ret = set_primary_common(mntpt, sign);
7497 7646
7498 7647 (void) umount_top_dataset(pool, mnted, mntpt);
7499 7648
7500 7649 free(pool);
7501 7650
7502 7651 INJECT_ERROR1("SET_PRIMARY_ZFS_FAIL", ret = 1);
7503 7652 if (ret == 0) {
7504 7653 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
7505 7654 } else {
7506 7655 BAM_DPRINTF(("%s: returning FAILURE\n", fcn));
7507 7656 }
7508 7657
7509 7658 return (ret);
7510 7659 }
7511 7660
7512 7661 static int
7513 7662 set_primary(char *osroot, char *osdev, char *sign, char *fstype)
7514 7663 {
7515 7664 const char *fcn = "set_primary()";
7516 7665 int ret;
7517 7666
7518 7667 INJECT_ERROR1("SET_PRIMARY_FSTYPE", fstype = "foofs");
7519 7668 if (strcmp(fstype, "ufs") == 0) {
7520 7669 BAM_DPRINTF(("%s: setting UFS primary sign\n", fcn));
7521 7670 ret = set_primary_ufs(osroot, sign);
7522 7671 } else if (strcmp(fstype, "zfs") == 0) {
7523 7672 BAM_DPRINTF(("%s: setting ZFS primary sign\n", fcn));
7524 7673 ret = set_primary_zfs(osdev, sign);
7525 7674 } else {
7526 7675 bam_error(_("boot signature not supported for fstype: %s\n"),
7527 7676 fstype);
7528 7677 ret = -1;
7529 7678 }
7530 7679
7531 7680 if (ret == 0) {
7532 7681 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
7533 7682 } else {
7534 7683 BAM_DPRINTF(("%s: returning FAILURE\n", fcn));
7535 7684 }
7536 7685
7537 7686 return (ret);
7538 7687 }
7539 7688
7540 7689 static int
7541 7690 ufs_add_to_sign_list(char *sign)
7542 7691 {
7543 7692 FILE *tfp;
7544 7693 char signline[MAXNAMELEN];
7545 7694 char cmd[PATH_MAX];
7546 7695 int ret;
7547 7696 int error;
7548 7697 const char *fcn = "ufs_add_to_sign_list()";
7549 7698
7550 7699 INJECT_ERROR1("ADD_TO_SIGN_LIST_NOT_UFS", sign = "pool_rpool5");
7551 7700 if (strncmp(sign, GRUBSIGN_UFS_PREFIX,
7552 7701 strlen(GRUBSIGN_UFS_PREFIX)) != 0) {
7553 7702 bam_error(_("invalid UFS boot signature %s\n"), sign);
7554 7703 (void) unlink(UFS_SIGNATURE_LIST);
7555 7704 return (-1);
7556 7705 }
7557 7706
7558 7707 /*
7559 7708 * most failures in this routine are not a fatal error
7560 7709 * We simply unlink the /var/run file and continue
7561 7710 */
7562 7711
7563 7712 ret = rename(UFS_SIGNATURE_LIST, UFS_SIGNATURE_LIST".tmp");
7564 7713 error = errno;
7565 7714 INJECT_ERROR1("ADD_TO_SIGN_LIST_RENAME", ret = -1);
7566 7715 if (ret == -1) {
7567 7716 bam_error(_("rename to file failed: %s: %s\n"),
7568 7717 UFS_SIGNATURE_LIST".tmp", strerror(error));
7569 7718 (void) unlink(UFS_SIGNATURE_LIST);
7570 7719 return (0);
7571 7720 }
7572 7721
7573 7722 tfp = fopen(UFS_SIGNATURE_LIST".tmp", "a");
7574 7723 error = errno;
7575 7724 INJECT_ERROR1("ADD_TO_SIGN_LIST_FOPEN", tfp = NULL);
7576 7725 if (tfp == NULL) {
7577 7726 bam_error(_("failed to open file: %s: %s\n"),
7578 7727 UFS_SIGNATURE_LIST".tmp", strerror(error));
7579 7728 (void) unlink(UFS_SIGNATURE_LIST".tmp");
7580 7729 return (0);
7581 7730 }
7582 7731
7583 7732 (void) snprintf(signline, sizeof (signline), "%s\n", sign);
7584 7733
7585 7734 ret = fputs(signline, tfp);
7586 7735 error = errno;
7587 7736 INJECT_ERROR1("ADD_TO_SIGN_LIST_FPUTS", ret = 0);
7588 7737 if (ret != strlen(signline)) {
7589 7738 bam_error(_("failed to write signature %s to signature "
7590 7739 "list: %s\n"), sign, strerror(error));
7591 7740 (void) fclose(tfp);
7592 7741 (void) unlink(UFS_SIGNATURE_LIST".tmp");
7593 7742 return (0);
7594 7743 }
7595 7744
7596 7745 ret = fclose(tfp);
7597 7746 error = errno;
7598 7747 INJECT_ERROR1("ADD_TO_SIGN_LIST_FCLOSE", ret = EOF);
7599 7748 if (ret == EOF) {
7600 7749 bam_error(_("failed to close file: %s: %s\n"),
7601 7750 UFS_SIGNATURE_LIST".tmp", strerror(error));
7602 7751 (void) unlink(UFS_SIGNATURE_LIST".tmp");
7603 7752 return (0);
7604 7753 }
7605 7754
7606 7755 /* Sort the list again */
7607 7756 (void) snprintf(cmd, sizeof (cmd),
7608 7757 "/usr/bin/sort -u %s.tmp > %s.sorted",
7609 7758 UFS_SIGNATURE_LIST, UFS_SIGNATURE_LIST);
7610 7759
7611 7760 ret = exec_cmd(cmd, NULL);
7612 7761 INJECT_ERROR1("ADD_TO_SIGN_LIST_SORT", ret = 1);
7613 7762 if (ret != 0) {
7614 7763 bam_error(_("error sorting GRUB UFS boot signatures\n"));
7615 7764 (void) unlink(UFS_SIGNATURE_LIST".sorted");
7616 7765 (void) unlink(UFS_SIGNATURE_LIST".tmp");
7617 7766 return (0);
7618 7767 }
7619 7768
7620 7769 (void) unlink(UFS_SIGNATURE_LIST".tmp");
7621 7770
7622 7771 ret = rename(UFS_SIGNATURE_LIST".sorted", UFS_SIGNATURE_LIST);
7623 7772 error = errno;
7624 7773 INJECT_ERROR1("ADD_TO_SIGN_LIST_RENAME2", ret = -1);
7625 7774 if (ret == -1) {
7626 7775 bam_error(_("rename to file failed: %s: %s\n"),
7627 7776 UFS_SIGNATURE_LIST, strerror(error));
7628 7777 (void) unlink(UFS_SIGNATURE_LIST".sorted");
7629 7778 return (0);
7630 7779 }
7631 7780
7632 7781 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
7633 7782
7634 7783 return (0);
7635 7784 }
7636 7785
7637 7786 static int
7638 7787 set_signature(char *osroot, char *osdev, char *sign, char *fstype)
7639 7788 {
7640 7789 int ret;
7641 7790 const char *fcn = "set_signature()";
7642 7791
7643 7792 BAM_DPRINTF(("%s: entered. args: %s %s %s %s\n", fcn,
7644 7793 osroot, osdev, sign, fstype));
7645 7794
7646 7795 ret = set_backup(osroot, osdev, sign, fstype);
7647 7796 INJECT_ERROR1("SET_SIGNATURE_BACKUP", ret = -1);
7648 7797 if (ret == -1) {
7649 7798 BAM_DPRINTF(("%s: returning FAILURE\n", fcn));
7650 7799 bam_error(_("failed to set backup sign (%s) for %s: %s\n"),
7651 7800 sign, osroot, osdev);
7652 7801 return (-1);
7653 7802 }
7654 7803
7655 7804 ret = set_primary(osroot, osdev, sign, fstype);
7656 7805 INJECT_ERROR1("SET_SIGNATURE_PRIMARY", ret = -1);
7657 7806
7658 7807 if (ret == 0) {
7659 7808 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
7660 7809 } else {
7661 7810 BAM_DPRINTF(("%s: returning FAILURE\n", fcn));
7662 7811 bam_error(_("failed to set primary sign (%s) for %s: %s\n"),
7663 7812 sign, osroot, osdev);
7664 7813
7665 7814 }
7666 7815 return (ret);
7667 7816 }
7668 7817
7669 7818 char *
7670 7819 get_grubsign(char *osroot, char *osdev)
7671 7820 {
7672 7821 char *grubsign; /* (<sign>,#,#) */
7673 7822 char *slice;
7674 7823 int fdiskpart;
7675 7824 char *sign;
7676 7825 char *fstype;
7677 7826 int ret;
7678 7827 const char *fcn = "get_grubsign()";
7679 7828
7680 7829 BAM_DPRINTF(("%s: entered. args: %s %s\n", fcn, osroot, osdev));
7681 7830 fstype = get_fstype(osroot);
7682 7831 INJECT_ERROR1("GET_GRUBSIGN_FSTYPE", fstype = NULL);
7683 7832 if (fstype == NULL) {
7684 7833 bam_error(_("failed to get fstype for %s\n"), osroot);
7685 7834 return (NULL);
7686 7835 }
7687 7836
7688 7837 sign = find_existing_sign(osroot, osdev, fstype);
7689 7838 INJECT_ERROR1("FIND_EXISTING_SIGN", sign = NULL);
7690 7839 if (sign == NULL) {
7691 7840 BAM_DPRINTF(("%s: no existing grubsign for %s: %s\n",
7692 7841 fcn, osroot, osdev));
7693 7842 sign = create_new_sign(osdev, fstype);
7694 7843 INJECT_ERROR1("CREATE_NEW_SIGN", sign = NULL);
7695 7844 if (sign == NULL) {
7696 7845 bam_error(_("failed to create GRUB boot signature for "
7697 7846 "device: %s\n"), osdev);
7698 7847 free(fstype);
7699 7848 return (NULL);
7700 7849 }
7701 7850 }
7702 7851
7703 7852 ret = set_signature(osroot, osdev, sign, fstype);
7704 7853 INJECT_ERROR1("SET_SIGNATURE_FAIL", ret = -1);
7705 7854 if (ret == -1) {
7706 7855 bam_error(_("failed to write GRUB boot signature for "
7707 7856 "device: %s\n"), osdev);
7708 7857 free(sign);
7709 7858 free(fstype);
7710 7859 (void) unlink(UFS_SIGNATURE_LIST);
7711 7860 return (NULL);
7712 7861 }
7713 7862
7714 7863 free(fstype);
7715 7864
7716 7865 if (bam_verbose)
7717 7866 bam_print(_("found or created GRUB signature %s for %s\n"),
7718 7867 sign, osdev);
7719 7868
7720 7869 fdiskpart = get_partition(osdev);
7721 7870 INJECT_ERROR1("GET_GRUBSIGN_FDISK", fdiskpart = PARTNO_NOTFOUND);
7722 7871 if (fdiskpart == PARTNO_NOTFOUND) {
7723 7872 bam_error(_("failed to determine fdisk partition: %s\n"),
7724 7873 osdev);
7725 7874 free(sign);
7726 7875 return (NULL);
7727 7876 }
7728 7877
7729 7878 slice = strrchr(osdev, 's');
7730 7879
7731 7880 if (fdiskpart == PARTNO_EFI) {
7732 7881 fdiskpart = atoi(&slice[1]);
7733 7882 slice = NULL;
7734 7883 }
7735 7884
7736 7885 grubsign = s_calloc(1, MAXNAMELEN + 10);
7737 7886 if (slice) {
7738 7887 (void) snprintf(grubsign, MAXNAMELEN + 10, "(%s,%d,%c)",
7739 7888 sign, fdiskpart, slice[1] + 'a' - '0');
7740 7889 } else
7741 7890 (void) snprintf(grubsign, MAXNAMELEN + 10, "(%s,%d)",
7742 7891 sign, fdiskpart);
7743 7892
7744 7893 free(sign);
7745 7894
7746 7895 BAM_DPRINTF(("%s: successfully created grubsign %s\n", fcn, grubsign));
7747 7896
7748 7897 return (grubsign);
7749 7898 }
7750 7899
7751 7900 static char *
7752 7901 get_title(char *rootdir)
7753 7902 {
7754 7903 static char title[80];
7755 7904 char *cp = NULL;
7756 7905 char release[PATH_MAX];
7757 7906 FILE *fp;
7758 7907 const char *fcn = "get_title()";
7759 7908
7760 7909 /* open the /etc/release file */
7761 7910 (void) snprintf(release, sizeof (release), "%s/etc/release", rootdir);
7762 7911
7763 7912 fp = fopen(release, "r");
7764 7913 if (fp == NULL) {
7765 7914 bam_error(_("failed to open file: %s: %s\n"), release,
7766 7915 strerror(errno));
7767 7916 cp = NULL;
7768 7917 goto out;
7769 7918 }
7770 7919
7771 7920 /* grab first line of /etc/release */
7772 7921 cp = s_fgets(title, sizeof (title), fp);
7773 7922 if (cp) {
7774 7923 while (isspace(*cp)) /* remove leading spaces */
7775 7924 cp++;
7776 7925 }
7777 7926
7778 7927 (void) fclose(fp);
7779 7928
7780 7929 out:
7781 7930 cp = cp ? cp : "Oracle Solaris";
7782 7931
7783 7932 BAM_DPRINTF(("%s: got title: %s\n", fcn, cp));
7784 7933
7785 7934 return (cp);
7786 7935 }
7787 7936
7788 7937 char *
7789 7938 get_special(char *mountp)
7790 7939 {
7791 7940 FILE *mntfp;
7792 7941 struct mnttab mp = {0};
7793 7942 struct mnttab mpref = {0};
7794 7943 int error;
7795 7944 int ret;
7796 7945 const char *fcn = "get_special()";
7797 7946
7798 7947 INJECT_ERROR1("GET_SPECIAL_MNTPT", mountp = NULL);
7799 7948 if (mountp == NULL) {
7800 7949 bam_error(_("cannot get special file: NULL mount-point\n"));
7801 7950 return (NULL);
7802 7951 }
7803 7952
7804 7953 mntfp = fopen(MNTTAB, "r");
7805 7954 error = errno;
7806 7955 INJECT_ERROR1("GET_SPECIAL_MNTTAB_OPEN", mntfp = NULL);
7807 7956 if (mntfp == NULL) {
7808 7957 bam_error(_("failed to open file: %s: %s\n"), MNTTAB,
7809 7958 strerror(error));
7810 7959 return (NULL);
7811 7960 }
7812 7961
7813 7962 if (*mountp == '\0')
7814 7963 mpref.mnt_mountp = "/";
7815 7964 else
7816 7965 mpref.mnt_mountp = mountp;
7817 7966
7818 7967 ret = getmntany(mntfp, &mp, &mpref);
7819 7968 INJECT_ERROR1("GET_SPECIAL_MNTTAB_SEARCH", ret = 1);
7820 7969 if (ret != 0) {
7821 7970 (void) fclose(mntfp);
7822 7971 BAM_DPRINTF(("%s: Cannot get special file: mount-point %s "
7823 7972 "not in mnttab\n", fcn, mountp));
7824 7973 return (NULL);
7825 7974 }
7826 7975 (void) fclose(mntfp);
7827 7976
7828 7977 BAM_DPRINTF(("%s: returning special: %s\n", fcn, mp.mnt_special));
7829 7978
7830 7979 return (s_strdup(mp.mnt_special));
7831 7980 }
7832 7981
7833 7982 static void
7834 7983 free_physarray(char **physarray, int n)
7835 7984 {
7836 7985 int i;
7837 7986 const char *fcn = "free_physarray()";
7838 7987
7839 7988 assert(physarray);
7840 7989 assert(n);
7841 7990
7842 7991 BAM_DPRINTF(("%s: entering args: %d\n", fcn, n));
7843 7992
7844 7993 for (i = 0; i < n; i++) {
7845 7994 free(physarray[i]);
7846 7995 }
7847 7996 free(physarray);
7848 7997
7849 7998 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
7850 7999 }
7851 8000
7852 8001 static int
7853 8002 zfs_get_physical(char *special, char ***physarray, int *n)
7854 8003 {
7855 8004 char sdup[PATH_MAX];
7856 8005 char cmd[PATH_MAX];
7857 8006 char dsk[PATH_MAX];
7858 8007 char *pool;
7859 8008 filelist_t flist = {0};
7860 8009 line_t *lp;
7861 8010 line_t *startlp;
7862 8011 char *comp1;
7863 8012 int i;
7864 8013 int ret;
7865 8014 const char *fcn = "zfs_get_physical()";
7866 8015
7867 8016 assert(special);
7868 8017
7869 8018 BAM_DPRINTF(("%s: entered. arg: %s\n", fcn, special));
7870 8019
7871 8020 INJECT_ERROR1("INVALID_ZFS_SPECIAL", special = "/foo");
7872 8021 if (special[0] == '/') {
7873 8022 bam_error(_("invalid device for ZFS filesystem: %s\n"),
7874 8023 special);
7875 8024 return (-1);
7876 8025 }
7877 8026
7878 8027 (void) strlcpy(sdup, special, sizeof (sdup));
7879 8028
7880 8029 pool = strtok(sdup, "/");
7881 8030 INJECT_ERROR1("ZFS_GET_PHYS_POOL", pool = NULL);
7882 8031 if (pool == NULL) {
7883 8032 bam_error(_("cannot derive ZFS pool from special: %s\n"),
7884 8033 special);
7885 8034 return (-1);
7886 8035 }
7887 8036
7888 8037 (void) snprintf(cmd, sizeof (cmd), "/sbin/zpool status %s", pool);
7889 8038
7890 8039 ret = exec_cmd(cmd, &flist);
7891 8040 INJECT_ERROR1("ZFS_GET_PHYS_STATUS", ret = 1);
7892 8041 if (ret != 0) {
7893 8042 bam_error(_("cannot get zpool status for pool: %s\n"), pool);
7894 8043 return (-1);
7895 8044 }
7896 8045
7897 8046 INJECT_ERROR1("ZFS_GET_PHYS_STATUS_OUT", flist.head = NULL);
7898 8047 if (flist.head == NULL) {
7899 8048 bam_error(_("bad zpool status for pool=%s\n"), pool);
7900 8049 filelist_free(&flist);
7901 8050 return (-1);
7902 8051 }
7903 8052
7904 8053 for (lp = flist.head; lp; lp = lp->next) {
7905 8054 BAM_DPRINTF(("%s: strtok() zpool status line=%s\n",
7906 8055 fcn, lp->line));
7907 8056 comp1 = strtok(lp->line, " \t");
7908 8057 if (comp1 == NULL) {
7909 8058 free(lp->line);
7910 8059 lp->line = NULL;
7911 8060 } else {
7912 8061 comp1 = s_strdup(comp1);
7913 8062 free(lp->line);
7914 8063 lp->line = comp1;
7915 8064 }
7916 8065 }
7917 8066
7918 8067 for (lp = flist.head; lp; lp = lp->next) {
7919 8068 if (lp->line == NULL)
7920 8069 continue;
7921 8070 if (strcmp(lp->line, pool) == 0) {
7922 8071 BAM_DPRINTF(("%s: found pool name: %s in zpool "
7923 8072 "status\n", fcn, pool));
7924 8073 break;
7925 8074 }
7926 8075 }
7927 8076
7928 8077 if (lp == NULL) {
7929 8078 bam_error(_("no pool name %s in zpool status\n"), pool);
7930 8079 filelist_free(&flist);
7931 8080 return (-1);
7932 8081 }
7933 8082
7934 8083 startlp = lp->next;
7935 8084 for (i = 0, lp = startlp; lp; lp = lp->next) {
7936 8085 if (lp->line == NULL)
7937 8086 continue;
7938 8087 if (strcmp(lp->line, "mirror") == 0)
7939 8088 continue;
7940 8089 if (lp->line[0] == '\0' || strcmp(lp->line, "errors:") == 0)
7941 8090 break;
7942 8091 i++;
7943 8092 BAM_DPRINTF(("%s: counting phys slices in zpool status: %d\n",
7944 8093 fcn, i));
7945 8094 }
7946 8095
7947 8096 if (i == 0) {
7948 8097 bam_error(_("no physical device in zpool status for pool=%s\n"),
7949 8098 pool);
7950 8099 filelist_free(&flist);
7951 8100 return (-1);
7952 8101 }
7953 8102
7954 8103 *n = i;
7955 8104 *physarray = s_calloc(*n, sizeof (char *));
7956 8105 for (i = 0, lp = startlp; lp; lp = lp->next) {
7957 8106 if (lp->line == NULL)
7958 8107 continue;
7959 8108 if (strcmp(lp->line, "mirror") == 0)
7960 8109 continue;
7961 8110 if (strcmp(lp->line, "errors:") == 0)
7962 8111 break;
7963 8112 if (strncmp(lp->line, "/dev/dsk/", strlen("/dev/dsk/")) != 0 &&
7964 8113 strncmp(lp->line, "/dev/rdsk/",
7965 8114 strlen("/dev/rdsk/")) != 0) {
7966 8115 (void) snprintf(dsk, sizeof (dsk), "/dev/rdsk/%s",
7967 8116 lp->line);
7968 8117 } else {
7969 8118 (void) strlcpy(dsk, lp->line, sizeof (dsk));
7970 8119 }
7971 8120 BAM_DPRINTF(("%s: adding phys slice=%s from pool %s status\n",
7972 8121 fcn, dsk, pool));
7973 8122 (*physarray)[i++] = s_strdup(dsk);
7974 8123 }
7975 8124
7976 8125 assert(i == *n);
7977 8126
7978 8127 filelist_free(&flist);
7979 8128
7980 8129 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
7981 8130 return (0);
7982 8131 }
7983 8132
7984 8133 static int
7985 8134 get_physical(char *menu_root, char ***physarray, int *n)
7986 8135 {
7987 8136 char *special;
7988 8137 int ret;
7989 8138 const char *fcn = "get_physical()";
7990 8139
7991 8140 assert(menu_root);
7992 8141 assert(physarray);
7993 8142 assert(n);
7994 8143
7995 8144 *physarray = NULL;
7996 8145 *n = 0;
7997 8146
7998 8147 BAM_DPRINTF(("%s: entered. arg: %s\n", fcn, menu_root));
7999 8148
8000 8149 /* First get the device special file from /etc/mnttab */
8001 8150 special = get_special(menu_root);
8002 8151 INJECT_ERROR1("GET_PHYSICAL_SPECIAL", special = NULL);
8003 8152 if (special == NULL) {
8004 8153 bam_error(_("cannot get special file for mount-point: %s\n"),
8005 8154 menu_root);
8006 8155 return (-1);
8007 8156 }
8008 8157
8009 8158 /* If already a physical device nothing to do */
8010 8159 if (strncmp(special, "/dev/dsk/", strlen("/dev/dsk/")) == 0 ||
8011 8160 strncmp(special, "/dev/rdsk/", strlen("/dev/rdsk/")) == 0) {
8012 8161 BAM_DPRINTF(("%s: got physical device already directly for "
8013 8162 "menu_root=%s special=%s\n", fcn, menu_root, special));
8014 8163 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
8015 8164 *physarray = s_calloc(1, sizeof (char *));
8016 8165 (*physarray)[0] = special;
8017 8166 *n = 1;
8018 8167 return (0);
8019 8168 }
8020 8169
8021 8170 if (is_zfs(menu_root)) {
8022 8171 ret = zfs_get_physical(special, physarray, n);
8023 8172 } else {
8024 8173 bam_error(_("cannot derive physical device for %s (%s), "
8025 8174 "unsupported filesystem\n"), menu_root, special);
8026 8175 ret = -1;
8027 8176 }
8028 8177
8029 8178 free(special);
8030 8179
8031 8180 INJECT_ERROR1("GET_PHYSICAL_RET", ret = -1);
8032 8181 if (ret == -1) {
8033 8182 BAM_DPRINTF(("%s: returning FAILURE\n", fcn));
8034 8183 } else {
8035 8184 int i;
8036 8185 assert (*n > 0);
8037 8186 for (i = 0; i < *n; i++) {
8038 8187 BAM_DPRINTF(("%s: returning physical=%s\n",
8039 8188 fcn, (*physarray)[i]));
8040 8189 }
8041 8190 }
8042 8191
8043 8192 return (ret);
8044 8193 }
8045 8194
8046 8195 static int
8047 8196 is_bootdisk(char *osroot, char *physical)
8048 8197 {
8049 8198 int ret;
8050 8199 char *grubroot;
8051 8200 char *bootp;
8052 8201 const char *fcn = "is_bootdisk()";
8053 8202
8054 8203 assert(osroot);
8055 8204 assert(physical);
8056 8205
8057 8206 BAM_DPRINTF(("%s: entered. args: %s %s\n", fcn, osroot, physical));
8058 8207
8059 8208 bootp = strstr(physical, "p0:boot");
8060 8209 if (bootp)
8061 8210 *bootp = '\0';
8062 8211 /*
8063 8212 * We just want the BIOS mapping for menu disk.
8064 8213 * Don't pass menu_root to get_grubroot() as the
8065 8214 * check that it is used for is not relevant here.
8066 8215 * The osroot is immaterial as well - it is only used to
8067 8216 * to find create_diskmap script. Everything hinges on
8068 8217 * "physical"
8069 8218 */
8070 8219 grubroot = get_grubroot(osroot, physical, NULL);
8071 8220
8072 8221 INJECT_ERROR1("IS_BOOTDISK_GRUBROOT", grubroot = NULL);
8073 8222 if (grubroot == NULL) {
8074 8223 if (bam_verbose)
8075 8224 bam_error(_("cannot determine BIOS disk ID 'hd?' for "
8076 8225 "disk: %s\n"), physical);
8077 8226 return (0);
8078 8227 }
8079 8228 ret = grubroot[3] == '0';
8080 8229 free(grubroot);
8081 8230
8082 8231 BAM_DPRINTF(("%s: returning ret = %d\n", fcn, ret));
8083 8232
8084 8233 return (ret);
8085 8234 }
8086 8235
8087 8236 /*
8088 8237 * Check if menu is on the boot device
8089 8238 * Return 0 (false) on error
8090 8239 */
8091 8240 static int
8092 8241 menu_on_bootdisk(char *osroot, char *menu_root)
8093 8242 {
8094 8243 char **physarray;
8095 8244 int ret;
8096 8245 int n;
8097 8246 int i;
8098 8247 int on_bootdisk;
8099 8248 const char *fcn = "menu_on_bootdisk()";
8100 8249
8101 8250 BAM_DPRINTF(("%s: entered. args: %s %s\n", fcn, osroot, menu_root));
8102 8251
8103 8252 ret = get_physical(menu_root, &physarray, &n);
8104 8253 INJECT_ERROR1("MENU_ON_BOOTDISK_PHYSICAL", ret = -1);
8105 8254 if (ret != 0) {
8106 8255 bam_error(_("cannot get physical device special file for menu "
8107 8256 "root: %s\n"), menu_root);
8108 8257 return (0);
8109 8258 }
8110 8259
8111 8260 assert(physarray);
8112 8261 assert(n > 0);
8113 8262
8114 8263 on_bootdisk = 0;
8115 8264 for (i = 0; i < n; i++) {
8116 8265 assert(strncmp(physarray[i], "/dev/dsk/",
8117 8266 strlen("/dev/dsk/")) == 0 ||
8118 8267 strncmp(physarray[i], "/dev/rdsk/",
8119 8268 strlen("/dev/rdsk/")) == 0);
8120 8269
8121 8270 BAM_DPRINTF(("%s: checking if phys-device=%s is on bootdisk\n",
8122 8271 fcn, physarray[i]));
8123 8272 if (is_bootdisk(osroot, physarray[i])) {
8124 8273 on_bootdisk = 1;
8125 8274 BAM_DPRINTF(("%s: phys-device=%s *IS* on bootdisk\n",
8126 8275 fcn, physarray[i]));
8127 8276 }
8128 8277 }
8129 8278
8130 8279 free_physarray(physarray, n);
8131 8280
8132 8281 INJECT_ERROR1("ON_BOOTDISK_YES", on_bootdisk = 1);
8133 8282 INJECT_ERROR1("ON_BOOTDISK_NO", on_bootdisk = 0);
8134 8283 if (on_bootdisk) {
8135 8284 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
8136 8285 } else {
8137 8286 BAM_DPRINTF(("%s: returning FAILURE\n", fcn));
8138 8287 }
8139 8288
8140 8289 return (on_bootdisk);
8141 8290 }
8142 8291
8143 8292 void
8144 8293 bam_add_line(menu_t *mp, entry_t *entry, line_t *prev, line_t *lp)
8145 8294 {
8146 8295 const char *fcn = "bam_add_line()";
8147 8296
8148 8297 assert(mp);
8149 8298 assert(entry);
8150 8299 assert(prev);
8151 8300 assert(lp);
8152 8301
8153 8302 lp->next = prev->next;
8154 8303 if (prev->next) {
8155 8304 BAM_DPRINTF(("%s: previous next exists\n", fcn));
8156 8305 prev->next->prev = lp;
8157 8306 } else {
8158 8307 BAM_DPRINTF(("%s: previous next does not exist\n", fcn));
8159 8308 }
8160 8309 prev->next = lp;
8161 8310 lp->prev = prev;
8162 8311
8163 8312 if (entry->end == prev) {
8164 8313 BAM_DPRINTF(("%s: last line in entry\n", fcn));
8165 8314 entry->end = lp;
8166 8315 }
8167 8316 if (mp->end == prev) {
8168 8317 assert(lp->next == NULL);
8169 8318 mp->end = lp;
8170 8319 BAM_DPRINTF(("%s: last line in menu\n", fcn));
8171 8320 }
8172 8321 }
8173 8322
8174 8323 /*
8175 8324 * look for matching bootadm entry with specified parameters
8176 8325 * Here are the rules (based on existing usage):
8177 8326 * - If title is specified, match on title only
8178 8327 * - Else, match on root/findroot, kernel, and module.
8179 8328 * Note that, if root_opt is non-zero, the absence of
8180 8329 * root line is considered a match.
8181 8330 */
8182 8331 static entry_t *
8183 8332 find_boot_entry(
8184 8333 menu_t *mp,
8185 8334 char *title,
8186 8335 char *kernel,
8187 8336 char *findroot,
8188 8337 char *root,
8189 8338 char *module,
8190 8339 int root_opt,
8191 8340 int *entry_num)
8192 8341 {
8193 8342 int i;
8194 8343 line_t *lp;
8195 8344 entry_t *ent;
8196 8345 const char *fcn = "find_boot_entry()";
8197 8346
8198 8347 if (entry_num)
8199 8348 *entry_num = BAM_ERROR;
8200 8349
8201 8350 /* find matching entry */
8202 8351 for (i = 0, ent = mp->entries; ent; i++, ent = ent->next) {
8203 8352 lp = ent->start;
8204 8353
8205 8354 /* first line of entry must be bootadm comment */
8206 8355 lp = ent->start;
8207 8356 if (lp->flags != BAM_COMMENT ||
8208 8357 strcmp(lp->arg, BAM_BOOTADM_HDR) != 0) {
8209 8358 continue;
8210 8359 }
8211 8360
8212 8361 /* advance to title line */
8213 8362 lp = lp->next;
8214 8363 if (title) {
8215 8364 if (lp->flags == BAM_TITLE && lp->arg &&
8216 8365 strcmp(lp->arg, title) == 0) {
8217 8366 BAM_DPRINTF(("%s: matched title: %s\n",
8218 8367 fcn, title));
8219 8368 break;
8220 8369 }
8221 8370 BAM_DPRINTF(("%s: no match title: %s, %s\n",
8222 8371 fcn, title, lp->arg));
8223 8372 continue; /* check title only */
8224 8373 }
8225 8374
8226 8375 lp = lp->next; /* advance to root line */
8227 8376 if (lp == NULL) {
8228 8377 continue;
8229 8378 } else if (lp->cmd != NULL &&
8230 8379 strcmp(lp->cmd, menu_cmds[FINDROOT_CMD]) == 0) {
8231 8380 INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_FINDROOT",
8232 8381 findroot = NULL);
8233 8382 if (findroot == NULL) {
8234 8383 BAM_DPRINTF(("%s: no match line has findroot, "
8235 8384 "we don't: %s\n", fcn, lp->arg));
8236 8385 continue;
8237 8386 }
8238 8387 /* findroot command found, try match */
8239 8388 if (strcmp(lp->arg, findroot) != 0) {
8240 8389 BAM_DPRINTF(("%s: no match findroot: %s, %s\n",
8241 8390 fcn, findroot, lp->arg));
8242 8391 continue;
8243 8392 }
8244 8393 BAM_DPRINTF(("%s: matched findroot: %s\n",
8245 8394 fcn, findroot));
8246 8395 lp = lp->next; /* advance to kernel line */
8247 8396 } else if (lp->cmd != NULL &&
8248 8397 strcmp(lp->cmd, menu_cmds[ROOT_CMD]) == 0) {
8249 8398 INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_ROOT", root = NULL);
8250 8399 if (root == NULL) {
8251 8400 BAM_DPRINTF(("%s: no match, line has root, we "
8252 8401 "don't: %s\n", fcn, lp->arg));
8253 8402 continue;
8254 8403 }
8255 8404 /* root cmd found, try match */
8256 8405 if (strcmp(lp->arg, root) != 0) {
8257 8406 BAM_DPRINTF(("%s: no match root: %s, %s\n",
8258 8407 fcn, root, lp->arg));
8259 8408 continue;
8260 8409 }
8261 8410 BAM_DPRINTF(("%s: matched root: %s\n", fcn, root));
8262 8411 lp = lp->next; /* advance to kernel line */
8263 8412 } else {
8264 8413 INJECT_ERROR1("FIND_BOOT_ENTRY_ROOT_OPT_NO",
8265 8414 root_opt = 0);
8266 8415 INJECT_ERROR1("FIND_BOOT_ENTRY_ROOT_OPT_YES",
8267 8416 root_opt = 1);
8268 8417 /* no root command, see if root is optional */
8269 8418 if (root_opt == 0) {
8270 8419 BAM_DPRINTF(("%s: root NOT optional\n", fcn));
8271 8420 continue;
8272 8421 }
8273 8422 BAM_DPRINTF(("%s: root IS optional\n", fcn));
8274 8423 }
8275 8424
8276 8425 if (lp == NULL || lp->next == NULL) {
8277 8426 continue;
8278 8427 }
8279 8428
8280 8429 if (kernel &&
8281 8430 (!check_cmd(lp->cmd, KERNEL_CMD, lp->arg, kernel))) {
8282 8431 if (!(ent->flags & BAM_ENTRY_FAILSAFE) ||
8283 8432 !(ent->flags & BAM_ENTRY_DBOOT) ||
8284 8433 strcmp(kernel, DIRECT_BOOT_FAILSAFE_LINE) != 0)
8285 8434 continue;
8286 8435
8287 8436 ent->flags |= BAM_ENTRY_UPGFSKERNEL;
8288 8437
8289 8438 }
8290 8439 BAM_DPRINTF(("%s: kernel match: %s, %s\n", fcn,
8291 8440 kernel, lp->arg));
8292 8441
8293 8442 /*
8294 8443 * Check for matching module entry (failsafe or normal).
8295 8444 * If it fails to match, we go around the loop again.
8296 8445 * For xpv entries, there are two module lines, so we
8297 8446 * do the check twice.
8298 8447 */
8299 8448 lp = lp->next; /* advance to module line */
8300 8449 if (check_cmd(lp->cmd, MODULE_CMD, lp->arg, module) ||
8301 8450 (((lp = lp->next) != NULL) &&
8302 8451 check_cmd(lp->cmd, MODULE_CMD, lp->arg, module))) {
8303 8452 /* match found */
8304 8453 BAM_DPRINTF(("%s: module match: %s, %s\n", fcn,
8305 8454 module, lp->arg));
8306 8455 break;
8307 8456 }
8308 8457
8309 8458 if (strcmp(module, FAILSAFE_ARCHIVE) == 0 &&
8310 8459 (strcmp(lp->prev->arg, FAILSAFE_ARCHIVE_32) == 0 ||
8311 8460 strcmp(lp->prev->arg, FAILSAFE_ARCHIVE_64) == 0)) {
8312 8461 ent->flags |= BAM_ENTRY_UPGFSMODULE;
8313 8462 break;
8314 8463 }
8315 8464
8316 8465 }
8317 8466
8318 8467 if (ent && entry_num) {
8319 8468 *entry_num = i;
8320 8469 }
8321 8470
8322 8471 if (ent) {
8323 8472 BAM_DPRINTF(("%s: returning ret = %d\n", fcn, i));
8324 8473 } else {
8325 8474 BAM_DPRINTF(("%s: returning ret = %d\n", fcn, BAM_ERROR));
8326 8475 }
8327 8476 return (ent);
8328 8477 }
8329 8478
8330 8479 static int
8331 8480 update_boot_entry(menu_t *mp, char *title, char *findroot, char *root,
8332 8481 char *kernel, char *mod_kernel, char *module, int root_opt)
8333 8482 {
8334 8483 int i;
8335 8484 int change_kernel = 0;
8336 8485 entry_t *ent;
8337 8486 line_t *lp;
8338 8487 line_t *tlp;
8339 8488 char linebuf[BAM_MAXLINE];
8340 8489 const char *fcn = "update_boot_entry()";
8341 8490
8342 8491 /* note: don't match on title, it's updated on upgrade */
8343 8492 ent = find_boot_entry(mp, NULL, kernel, findroot, root, module,
8344 8493 root_opt, &i);
8345 8494 if ((ent == NULL) && (bam_direct == BAM_DIRECT_DBOOT)) {
8346 8495 /*
8347 8496 * We may be upgrading a kernel from multiboot to
8348 8497 * directboot. Look for a multiboot entry. A multiboot
8349 8498 * entry will not have a findroot line.
8350 8499 */
8351 8500 ent = find_boot_entry(mp, NULL, "multiboot", NULL, root,
8352 8501 MULTIBOOT_ARCHIVE, root_opt, &i);
8353 8502 if (ent != NULL) {
8354 8503 BAM_DPRINTF(("%s: upgrading entry from dboot to "
8355 8504 "multiboot: root = %s\n", fcn, root));
8356 8505 change_kernel = 1;
8357 8506 }
8358 8507 } else if (ent) {
8359 8508 BAM_DPRINTF(("%s: found entry with matching findroot: %s\n",
8360 8509 fcn, findroot));
8361 8510 }
8362 8511
8363 8512 if (ent == NULL) {
8364 8513 BAM_DPRINTF(("%s: boot entry not found in menu. Creating "
8365 8514 "new entry, findroot = %s\n", fcn, findroot));
8366 8515 return (add_boot_entry(mp, title, findroot,
8367 8516 kernel, mod_kernel, module, NULL));
8368 8517 }
8369 8518
8370 8519 /* replace title of existing entry and update findroot line */
8371 8520 lp = ent->start;
8372 8521 lp = lp->next; /* title line */
8373 8522 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
8374 8523 menu_cmds[TITLE_CMD], menu_cmds[SEP_CMD], title);
8375 8524 free(lp->arg);
8376 8525 free(lp->line);
8377 8526 lp->arg = s_strdup(title);
8378 8527 lp->line = s_strdup(linebuf);
8379 8528 BAM_DPRINTF(("%s: changing title to: %s\n", fcn, title));
8380 8529
8381 8530 tlp = lp; /* title line */
8382 8531 lp = lp->next; /* root line */
8383 8532
8384 8533 /* if no root or findroot command, create a new line_t */
8385 8534 if ((lp->cmd != NULL) && (strcmp(lp->cmd, menu_cmds[ROOT_CMD]) != 0 &&
8386 8535 strcmp(lp->cmd, menu_cmds[FINDROOT_CMD]) != 0)) {
8387 8536 lp = s_calloc(1, sizeof (line_t));
8388 8537 bam_add_line(mp, ent, tlp, lp);
8389 8538 } else {
8390 8539 if (lp->cmd != NULL)
8391 8540 free(lp->cmd);
8392 8541
8393 8542 free(lp->sep);
8394 8543 free(lp->arg);
8395 8544 free(lp->line);
8396 8545 }
8397 8546
8398 8547 lp->cmd = s_strdup(menu_cmds[FINDROOT_CMD]);
8399 8548 lp->sep = s_strdup(menu_cmds[SEP_CMD]);
8400 8549 lp->arg = s_strdup(findroot);
8401 8550 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
8402 8551 menu_cmds[FINDROOT_CMD], menu_cmds[SEP_CMD], findroot);
8403 8552 lp->line = s_strdup(linebuf);
8404 8553 BAM_DPRINTF(("%s: adding findroot line: %s\n", fcn, findroot));
8405 8554
8406 8555 /* kernel line */
8407 8556 lp = lp->next;
8408 8557
8409 8558 if (ent->flags & BAM_ENTRY_UPGFSKERNEL) {
8410 8559 char *params = NULL;
8411 8560
8412 8561 params = strstr(lp->line, "-s");
8413 8562 if (params != NULL)
8414 8563 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s%s",
8415 8564 menu_cmds[KERNEL_DOLLAR_CMD], menu_cmds[SEP_CMD],
8416 8565 kernel, params+2);
8417 8566 else
8418 8567 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
8419 8568 menu_cmds[KERNEL_DOLLAR_CMD], menu_cmds[SEP_CMD],
8420 8569 kernel);
8421 8570
8422 8571 if (lp->cmd != NULL)
8423 8572 free(lp->cmd);
8424 8573
8425 8574 free(lp->arg);
8426 8575 free(lp->line);
8427 8576 lp->cmd = s_strdup(menu_cmds[KERNEL_DOLLAR_CMD]);
8428 8577 lp->arg = s_strdup(strstr(linebuf, "/"));
8429 8578 lp->line = s_strdup(linebuf);
8430 8579 ent->flags &= ~BAM_ENTRY_UPGFSKERNEL;
8431 8580 BAM_DPRINTF(("%s: adding new kernel$ line: %s\n",
8432 8581 fcn, lp->prev->cmd));
8433 8582 }
8434 8583
8435 8584 if (change_kernel) {
8436 8585 /*
8437 8586 * We're upgrading from multiboot to directboot.
8438 8587 */
8439 8588 if (lp->cmd != NULL &&
8440 8589 strcmp(lp->cmd, menu_cmds[KERNEL_CMD]) == 0) {
8441 8590 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
8442 8591 menu_cmds[KERNEL_DOLLAR_CMD], menu_cmds[SEP_CMD],
8443 8592 kernel);
8444 8593 free(lp->cmd);
8445 8594 free(lp->arg);
8446 8595 free(lp->line);
8447 8596 lp->cmd = s_strdup(menu_cmds[KERNEL_DOLLAR_CMD]);
8448 8597 lp->arg = s_strdup(kernel);
8449 8598 lp->line = s_strdup(linebuf);
8450 8599 lp = lp->next;
8451 8600 BAM_DPRINTF(("%s: adding new kernel$ line: %s\n",
8452 8601 fcn, kernel));
8453 8602 }
8454 8603 if (lp->cmd != NULL &&
8455 8604 strcmp(lp->cmd, menu_cmds[MODULE_CMD]) == 0) {
8456 8605 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
8457 8606 menu_cmds[MODULE_DOLLAR_CMD], menu_cmds[SEP_CMD],
8458 8607 module);
8459 8608 free(lp->cmd);
8460 8609 free(lp->arg);
8461 8610 free(lp->line);
8462 8611 lp->cmd = s_strdup(menu_cmds[MODULE_DOLLAR_CMD]);
8463 8612 lp->arg = s_strdup(module);
8464 8613 lp->line = s_strdup(linebuf);
8465 8614 lp = lp->next;
8466 8615 BAM_DPRINTF(("%s: adding new module$ line: %s\n",
8467 8616 fcn, module));
8468 8617 }
8469 8618 }
8470 8619
8471 8620 /* module line */
8472 8621 lp = lp->next;
8473 8622
8474 8623 if (ent->flags & BAM_ENTRY_UPGFSMODULE) {
8475 8624 if (lp->cmd != NULL &&
8476 8625 strcmp(lp->cmd, menu_cmds[MODULE_CMD]) == 0) {
8477 8626 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
8478 8627 menu_cmds[MODULE_DOLLAR_CMD], menu_cmds[SEP_CMD],
8479 8628 module);
8480 8629 free(lp->cmd);
8481 8630 free(lp->arg);
8482 8631 free(lp->line);
8483 8632 lp->cmd = s_strdup(menu_cmds[MODULE_DOLLAR_CMD]);
8484 8633 lp->arg = s_strdup(module);
8485 8634 lp->line = s_strdup(linebuf);
8486 8635 lp = lp->next;
8487 8636 ent->flags &= ~BAM_ENTRY_UPGFSMODULE;
8488 8637 BAM_DPRINTF(("%s: adding new module$ line: %s\n",
8489 8638 fcn, module));
8490 8639 }
8491 8640 }
8492 8641
8493 8642 BAM_DPRINTF(("%s: returning ret = %d\n", fcn, i));
8494 8643 return (i);
8495 8644 }
8496 8645
8497 8646 int
8498 8647 root_optional(char *osroot, char *menu_root)
8499 8648 {
8500 8649 char *ospecial;
8501 8650 char *mspecial;
8502 8651 char *slash;
8503 8652 int root_opt;
8504 8653 int ret1;
8505 8654 int ret2;
8506 8655 const char *fcn = "root_optional()";
8507 8656
8508 8657 BAM_DPRINTF(("%s: entered. args: %s %s\n", fcn, osroot, menu_root));
8509 8658
8510 8659 /*
8511 8660 * For all filesystems except ZFS, a straight compare of osroot
8512 8661 * and menu_root will tell us if root is optional.
8513 8662 * For ZFS, the situation is complicated by the fact that
8514 8663 * menu_root and osroot are always different
8515 8664 */
8516 8665 ret1 = is_zfs(osroot);
8517 8666 ret2 = is_zfs(menu_root);
8518 8667 INJECT_ERROR1("ROOT_OPT_NOT_ZFS", ret1 = 0);
8519 8668 if (!ret1 || !ret2) {
8520 8669 BAM_DPRINTF(("%s: one or more non-ZFS filesystems (%s, %s)\n",
8521 8670 fcn, osroot, menu_root));
8522 8671 root_opt = (strcmp(osroot, menu_root) == 0);
8523 8672 goto out;
8524 8673 }
8525 8674
8526 8675 ospecial = get_special(osroot);
8527 8676 INJECT_ERROR1("ROOT_OPTIONAL_OSPECIAL", ospecial = NULL);
8528 8677 if (ospecial == NULL) {
8529 8678 bam_error(_("failed to get special file for osroot: %s\n"),
8530 8679 osroot);
8531 8680 return (0);
8532 8681 }
8533 8682 BAM_DPRINTF(("%s: ospecial=%s for osroot=%s\n", fcn, ospecial, osroot));
8534 8683
8535 8684 mspecial = get_special(menu_root);
8536 8685 INJECT_ERROR1("ROOT_OPTIONAL_MSPECIAL", mspecial = NULL);
8537 8686 if (mspecial == NULL) {
8538 8687 bam_error(_("failed to get special file for menu_root: %s\n"),
8539 8688 menu_root);
8540 8689 free(ospecial);
8541 8690 return (0);
8542 8691 }
8543 8692 BAM_DPRINTF(("%s: mspecial=%s for menu_root=%s\n",
8544 8693 fcn, mspecial, menu_root));
8545 8694
8546 8695 slash = strchr(ospecial, '/');
8547 8696 if (slash)
8548 8697 *slash = '\0';
8549 8698 BAM_DPRINTF(("%s: FIXED ospecial=%s for osroot=%s\n",
8550 8699 fcn, ospecial, osroot));
8551 8700
8552 8701 root_opt = (strcmp(ospecial, mspecial) == 0);
8553 8702
8554 8703 free(ospecial);
8555 8704 free(mspecial);
8556 8705
8557 8706 out:
8558 8707 INJECT_ERROR1("ROOT_OPTIONAL_NO", root_opt = 0);
8559 8708 INJECT_ERROR1("ROOT_OPTIONAL_YES", root_opt = 1);
8560 8709 if (root_opt) {
8561 8710 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
8562 8711 } else {
8563 8712 BAM_DPRINTF(("%s: returning FAILURE\n", fcn));
8564 8713 }
8565 8714
8566 8715 return (root_opt);
8567 8716 }
8568 8717
8569 8718 /*ARGSUSED*/
8570 8719 static error_t
8571 8720 update_entry(menu_t *mp, char *menu_root, char *osdev)
8572 8721 {
8573 8722 int entry;
8574 8723 char *grubsign;
8575 8724 char *grubroot;
8576 8725 char *title;
8577 8726 char osroot[PATH_MAX];
8578 8727 char *failsafe_kernel = NULL;
8579 8728 struct stat sbuf;
8580 8729 char failsafe[256];
8581 8730 char failsafe_64[256];
8582 8731 int ret;
8583 8732 const char *fcn = "update_entry()";
8584 8733
8585 8734 assert(mp);
8586 8735 assert(menu_root);
8587 8736 assert(osdev);
8588 8737 assert(bam_root);
8589 8738
8590 8739 BAM_DPRINTF(("%s: entered. args: %s %s %s\n", fcn, menu_root, osdev,
8591 8740 bam_root));
8592 8741
8593 8742 (void) strlcpy(osroot, bam_root, sizeof (osroot));
8594 8743
8595 8744 title = get_title(osroot);
8596 8745 assert(title);
8597 8746
8598 8747 grubsign = get_grubsign(osroot, osdev);
8599 8748 INJECT_ERROR1("GET_GRUBSIGN_FAIL", grubsign = NULL);
8600 8749 if (grubsign == NULL) {
8601 8750 bam_error(_("failed to get grubsign for root: %s, device %s\n"),
8602 8751 osroot, osdev);
8603 8752 return (BAM_ERROR);
8604 8753 }
8605 8754
8606 8755 /*
8607 8756 * It is not a fatal error if get_grubroot() fails
8608 8757 * We no longer rely on biosdev to populate the
8609 8758 * menu
8610 8759 */
8611 8760 grubroot = get_grubroot(osroot, osdev, menu_root);
8612 8761 INJECT_ERROR1("GET_GRUBROOT_FAIL", grubroot = NULL);
8613 8762 if (grubroot) {
8614 8763 BAM_DPRINTF(("%s: get_grubroot success. osroot=%s, osdev=%s, "
8615 8764 "menu_root=%s\n", fcn, osroot, osdev, menu_root));
8616 8765 } else {
8617 8766 BAM_DPRINTF(("%s: get_grubroot failed. osroot=%s, osdev=%s, "
8618 8767 "menu_root=%s\n", fcn, osroot, osdev, menu_root));
8619 8768 }
8620 8769
8621 8770 /* add the entry for normal Solaris */
8622 8771 INJECT_ERROR1("UPDATE_ENTRY_MULTIBOOT",
8623 8772 bam_direct = BAM_DIRECT_MULTIBOOT);
8624 8773 if (bam_direct == BAM_DIRECT_DBOOT) {
8625 8774 entry = update_boot_entry(mp, title, grubsign, grubroot,
8626 8775 (bam_zfs ? DIRECT_BOOT_KERNEL_ZFS : DIRECT_BOOT_KERNEL),
8627 8776 NULL, DIRECT_BOOT_ARCHIVE,
8628 8777 root_optional(osroot, menu_root));
8629 8778 BAM_DPRINTF(("%s: updated boot entry bam_zfs=%d, "
8630 8779 "grubsign = %s\n", fcn, bam_zfs, grubsign));
8631 8780 if ((entry != BAM_ERROR) && (bam_is_hv == BAM_HV_PRESENT)) {
8632 8781 (void) update_boot_entry(mp, NEW_HV_ENTRY, grubsign,
8633 8782 grubroot, XEN_MENU, bam_zfs ?
8634 8783 XEN_KERNEL_MODULE_LINE_ZFS : XEN_KERNEL_MODULE_LINE,
8635 8784 DIRECT_BOOT_ARCHIVE,
8636 8785 root_optional(osroot, menu_root));
8637 8786 BAM_DPRINTF(("%s: updated HV entry bam_zfs=%d, "
8638 8787 "grubsign = %s\n", fcn, bam_zfs, grubsign));
8639 8788 }
8640 8789 } else {
8641 8790 entry = update_boot_entry(mp, title, grubsign, grubroot,
8642 8791 MULTI_BOOT, NULL, MULTIBOOT_ARCHIVE,
8643 8792 root_optional(osroot, menu_root));
8644 8793
8645 8794 BAM_DPRINTF(("%s: updated MULTIBOOT entry grubsign = %s\n",
8646 8795 fcn, grubsign));
8647 8796 }
8648 8797
8649 8798 /*
8650 8799 * Add the entry for failsafe archive. On a bfu'd system, the
8651 8800 * failsafe may be different than the installed kernel.
8652 8801 */
8653 8802 (void) snprintf(failsafe, sizeof (failsafe), "%s%s",
8654 8803 osroot, FAILSAFE_ARCHIVE_32);
8655 8804 (void) snprintf(failsafe_64, sizeof (failsafe_64), "%s%s",
8656 8805 osroot, FAILSAFE_ARCHIVE_64);
8657 8806
8658 8807 /*
8659 8808 * Check if at least one of the two archives exists
8660 8809 * Using $ISADIR as the default line, we have an entry which works
8661 8810 * for both the cases.
8662 8811 */
8663 8812
8664 8813 if (stat(failsafe, &sbuf) == 0 || stat(failsafe_64, &sbuf) == 0) {
8665 8814
8666 8815 /* Figure out where the kernel line should point */
8667 8816 (void) snprintf(failsafe, sizeof (failsafe), "%s%s", osroot,
8668 8817 DIRECT_BOOT_FAILSAFE_32);
8669 8818 (void) snprintf(failsafe_64, sizeof (failsafe_64), "%s%s",
8670 8819 osroot, DIRECT_BOOT_FAILSAFE_64);
8671 8820 if (stat(failsafe, &sbuf) == 0 ||
8672 8821 stat(failsafe_64, &sbuf) == 0) {
8673 8822 failsafe_kernel = DIRECT_BOOT_FAILSAFE_LINE;
8674 8823 } else {
8675 8824 (void) snprintf(failsafe, sizeof (failsafe), "%s%s",
8676 8825 osroot, MULTI_BOOT_FAILSAFE);
8677 8826 if (stat(failsafe, &sbuf) == 0) {
8678 8827 failsafe_kernel = MULTI_BOOT_FAILSAFE_LINE;
8679 8828 }
8680 8829 }
8681 8830 if (failsafe_kernel != NULL) {
8682 8831 (void) update_boot_entry(mp, FAILSAFE_TITLE, grubsign,
8683 8832 grubroot, failsafe_kernel, NULL, FAILSAFE_ARCHIVE,
8684 8833 root_optional(osroot, menu_root));
8685 8834 BAM_DPRINTF(("%s: updated FAILSAFE entry "
8686 8835 "failsafe_kernel = %s\n", fcn, failsafe_kernel));
8687 8836 }
8688 8837 }
8689 8838 free(grubroot);
8690 8839
8691 8840 INJECT_ERROR1("UPDATE_ENTRY_ERROR", entry = BAM_ERROR);
8692 8841 if (entry == BAM_ERROR) {
8693 8842 bam_error(_("failed to add boot entry with title=%s, grub "
8694 8843 "signature=%s\n"), title, grubsign);
8695 8844 free(grubsign);
8696 8845 return (BAM_ERROR);
8697 8846 }
8698 8847 free(grubsign);
8699 8848
8700 8849 update_numbering(mp);
8701 8850 ret = set_global(mp, menu_cmds[DEFAULT_CMD], entry);
8702 8851 INJECT_ERROR1("SET_DEFAULT_ERROR", ret = BAM_ERROR);
8703 8852 if (ret == BAM_ERROR) {
8704 8853 bam_error(_("failed to set GRUB menu default to %d\n"), entry);
8705 8854 }
8706 8855 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
8707 8856 return (BAM_WRITE);
8708 8857 }
8709 8858
8710 8859 static void
8711 8860 save_default_entry(menu_t *mp, const char *which)
8712 8861 {
8713 8862 int lineNum;
8714 8863 int entryNum;
8715 8864 int entry = 0; /* default is 0 */
8716 8865 char linebuf[BAM_MAXLINE];
8717 8866 line_t *lp = mp->curdefault;
8718 8867 const char *fcn = "save_default_entry()";
8719 8868
8720 8869 if (mp->start) {
8721 8870 lineNum = mp->end->lineNum;
8722 8871 entryNum = mp->end->entryNum;
8723 8872 } else {
8724 8873 lineNum = LINE_INIT;
8725 8874 entryNum = ENTRY_INIT;
8726 8875 }
8727 8876
8728 8877 if (lp)
8729 8878 entry = s_strtol(lp->arg);
8730 8879
8731 8880 (void) snprintf(linebuf, sizeof (linebuf), "#%s%d", which, entry);
8732 8881 BAM_DPRINTF(("%s: saving default to: %s\n", fcn, linebuf));
8733 8882 line_parser(mp, linebuf, &lineNum, &entryNum);
8734 8883 BAM_DPRINTF(("%s: saved default to lineNum=%d, entryNum=%d\n", fcn,
8735 8884 lineNum, entryNum));
8736 8885 }
8737 8886
8738 8887 static void
8739 8888 restore_default_entry(menu_t *mp, const char *which, line_t *lp)
8740 8889 {
8741 8890 int entry;
8742 8891 char *str;
8743 8892 const char *fcn = "restore_default_entry()";
8744 8893
8745 8894 if (lp == NULL) {
8746 8895 BAM_DPRINTF(("%s: NULL saved default\n", fcn));
8747 8896 return; /* nothing to restore */
8748 8897 }
8749 8898
8750 8899 BAM_DPRINTF(("%s: saved default string: %s\n", fcn, which));
8751 8900
8752 8901 str = lp->arg + strlen(which);
8753 8902 entry = s_strtol(str);
8754 8903 (void) set_global(mp, menu_cmds[DEFAULT_CMD], entry);
8755 8904
8756 8905 BAM_DPRINTF(("%s: restored default to entryNum: %d\n", fcn, entry));
8757 8906
8758 8907 /* delete saved old default line */
8759 8908 unlink_line(mp, lp);
8760 8909 line_free(lp);
8761 8910 }
8762 8911
8763 8912 /*
8764 8913 * This function is for supporting reboot with args.
8765 8914 * The opt value can be:
8766 8915 * NULL delete temp entry, if present
8767 8916 * entry=<n> switches default entry to <n>
8768 8917 * else treated as boot-args and setup a temperary menu entry
8769 8918 * and make it the default
8770 8919 * Note that we are always rebooting the current OS instance
8771 8920 * so osroot == / always.
8772 8921 */
8773 8922 #define REBOOT_TITLE "Solaris_reboot_transient"
8774 8923
8775 8924 /*ARGSUSED*/
8776 8925 static error_t
8777 8926 update_temp(menu_t *mp, char *dummy, char *opt)
8778 8927 {
8779 8928 int entry;
8780 8929 char *osdev;
8781 8930 char *fstype;
8782 8931 char *sign;
8783 8932 char *opt_ptr;
8784 8933 char *path;
8785 8934 char kernbuf[BUFSIZ];
8786 8935 char args_buf[BUFSIZ];
8787 8936 char signbuf[PATH_MAX];
8788 8937 int ret;
8789 8938 const char *fcn = "update_temp()";
8790 8939
8791 8940 assert(mp);
8792 8941 assert(dummy == NULL);
8793 8942
8794 8943 /* opt can be NULL */
8795 8944 BAM_DPRINTF(("%s: entered. arg: %s\n", fcn, opt ? opt : "<NULL>"));
8796 8945 BAM_DPRINTF(("%s: bam_alt_root: %d, bam_root: %s\n", fcn,
8797 8946 bam_alt_root, bam_root));
8798 8947
8799 8948 if (bam_alt_root || bam_rootlen != 1 ||
8800 8949 strcmp(bam_root, "/") != 0 ||
8801 8950 strcmp(rootbuf, "/") != 0) {
8802 8951 bam_error(_("an alternate root (%s) cannot be used with this "
8803 8952 "sub-command\n"), bam_root);
8804 8953 return (BAM_ERROR);
8805 8954 }
8806 8955
8807 8956 /* If no option, delete exiting reboot menu entry */
8808 8957 if (opt == NULL) {
8809 8958 entry_t *ent;
8810 8959 BAM_DPRINTF(("%s: opt is NULL\n", fcn));
8811 8960 ent = find_boot_entry(mp, REBOOT_TITLE, NULL, NULL,
8812 8961 NULL, NULL, 0, &entry);
8813 8962 if (ent == NULL) { /* not found is ok */
8814 8963 BAM_DPRINTF(("%s: transient entry not found\n", fcn));
8815 8964 return (BAM_SUCCESS);
8816 8965 }
8817 8966 (void) delete_boot_entry(mp, entry, DBE_PRINTERR);
8818 8967 restore_default_entry(mp, BAM_OLDDEF, mp->olddefault);
8819 8968 mp->olddefault = NULL;
8820 8969 BAM_DPRINTF(("%s: restored old default\n", fcn));
8821 8970 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
8822 8971 return (BAM_WRITE);
8823 8972 }
8824 8973
8825 8974 /* if entry= is specified, set the default entry */
8826 8975 if (strncmp(opt, "entry=", strlen("entry=")) == 0) {
8827 8976 int entryNum = s_strtol(opt + strlen("entry="));
8828 8977 BAM_DPRINTF(("%s: opt has entry=: %s\n", fcn, opt));
8829 8978 if (selector(mp, opt, &entry, NULL) == BAM_SUCCESS) {
8830 8979 /* this is entry=# option */
8831 8980 ret = set_global(mp, menu_cmds[DEFAULT_CMD], entry);
8832 8981 BAM_DPRINTF(("%s: default set to %d, "
8833 8982 "set_default ret=%d\n", fcn, entry, ret));
8834 8983 return (ret);
8835 8984 } else {
8836 8985 bam_error(_("failed to set GRUB menu default to %d\n"),
8837 8986 entryNum);
8838 8987 return (BAM_ERROR);
8839 8988 }
8840 8989 }
8841 8990
8842 8991 /*
8843 8992 * add a new menu entry based on opt and make it the default
8844 8993 */
8845 8994
8846 8995 fstype = get_fstype("/");
8847 8996 INJECT_ERROR1("REBOOT_FSTYPE_NULL", fstype = NULL);
8848 8997 if (fstype == NULL) {
8849 8998 bam_error(_("failed to determine filesystem type for \"/\". "
8850 8999 "Reboot with \narguments failed.\n"));
8851 9000 return (BAM_ERROR);
8852 9001 }
8853 9002
8854 9003 osdev = get_special("/");
8855 9004 INJECT_ERROR1("REBOOT_SPECIAL_NULL", osdev = NULL);
8856 9005 if (osdev == NULL) {
8857 9006 free(fstype);
8858 9007 bam_error(_("failed to find device special file for \"/\". "
8859 9008 "Reboot with \narguments failed.\n"));
8860 9009 return (BAM_ERROR);
8861 9010 }
8862 9011
8863 9012 sign = find_existing_sign("/", osdev, fstype);
8864 9013 INJECT_ERROR1("REBOOT_SIGN_NULL", sign = NULL);
8865 9014 if (sign == NULL) {
8866 9015 free(fstype);
8867 9016 free(osdev);
8868 9017 bam_error(_("failed to find boot signature. Reboot with "
8869 9018 "arguments failed.\n"));
8870 9019 return (BAM_ERROR);
8871 9020 }
8872 9021
8873 9022 free(osdev);
8874 9023 (void) strlcpy(signbuf, sign, sizeof (signbuf));
8875 9024 free(sign);
8876 9025
8877 9026 assert(strchr(signbuf, '(') == NULL && strchr(signbuf, ',') == NULL &&
8878 9027 strchr(signbuf, ')') == NULL);
8879 9028
8880 9029 /*
8881 9030 * There is no alternate root while doing reboot with args
8882 9031 * This version of bootadm is only delivered with a DBOOT
8883 9032 * version of Solaris.
8884 9033 */
8885 9034 INJECT_ERROR1("REBOOT_NOT_DBOOT", bam_direct = BAM_DIRECT_MULTIBOOT);
8886 9035 if (bam_direct != BAM_DIRECT_DBOOT) {
8887 9036 free(fstype);
8888 9037 bam_error(_("the root filesystem is not a dboot Solaris "
8889 9038 "instance. \nThis version of bootadm is not supported "
8890 9039 "on this version of Solaris.\n"));
8891 9040 return (BAM_ERROR);
8892 9041 }
8893 9042
8894 9043 /* add an entry for Solaris reboot */
8895 9044 if (opt[0] == '-') {
8896 9045 /* It's an option - first see if boot-file is set */
8897 9046 ret = get_kernel(mp, KERNEL_CMD, kernbuf, sizeof (kernbuf));
8898 9047 INJECT_ERROR1("REBOOT_GET_KERNEL", ret = BAM_ERROR);
8899 9048 if (ret != BAM_SUCCESS) {
8900 9049 free(fstype);
8901 9050 bam_error(_("reboot with arguments: error querying "
8902 9051 "current boot-file settings\n"));
8903 9052 return (BAM_ERROR);
8904 9053 }
8905 9054 if (kernbuf[0] == '\0')
8906 9055 (void) strlcpy(kernbuf, DIRECT_BOOT_KERNEL,
8907 9056 sizeof (kernbuf));
8908 9057 /*
8909 9058 * If this is a zfs file system and kernbuf does not
8910 9059 * have "-B $ZFS-BOOTFS" string yet, add it.
8911 9060 */
8912 9061 if (strcmp(fstype, "zfs") == 0 && !strstr(kernbuf, ZFS_BOOT)) {
8913 9062 (void) strlcat(kernbuf, " ", sizeof (kernbuf));
8914 9063 (void) strlcat(kernbuf, ZFS_BOOT, sizeof (kernbuf));
8915 9064 }
8916 9065 (void) strlcat(kernbuf, " ", sizeof (kernbuf));
8917 9066 (void) strlcat(kernbuf, opt, sizeof (kernbuf));
8918 9067 BAM_DPRINTF(("%s: reboot with args, option specified: "
8919 9068 "kern=%s\n", fcn, kernbuf));
8920 9069 } else if (opt[0] == '/') {
8921 9070 /* It's a full path, so write it out. */
8922 9071 (void) strlcpy(kernbuf, opt, sizeof (kernbuf));
8923 9072
8924 9073 /*
8925 9074 * If someone runs:
8926 9075 *
8927 9076 * # eeprom boot-args='-kd'
8928 9077 * # reboot /platform/i86pc/kernel/unix
8929 9078 *
8930 9079 * we want to use the boot-args as part of the boot
8931 9080 * line. On the other hand, if someone runs:
8932 9081 *
8933 9082 * # reboot "/platform/i86pc/kernel/unix -kd"
8934 9083 *
8935 9084 * we don't need to mess with boot-args. If there's
8936 9085 * no space in the options string, assume we're in the
8937 9086 * first case.
8938 9087 */
8939 9088 if (strchr(opt, ' ') == NULL) {
8940 9089 ret = get_kernel(mp, ARGS_CMD, args_buf,
8941 9090 sizeof (args_buf));
8942 9091 INJECT_ERROR1("REBOOT_GET_ARGS", ret = BAM_ERROR);
8943 9092 if (ret != BAM_SUCCESS) {
8944 9093 free(fstype);
8945 9094 bam_error(_("reboot with arguments: error "
8946 9095 "querying current boot-args settings\n"));
8947 9096 return (BAM_ERROR);
8948 9097 }
8949 9098
8950 9099 if (args_buf[0] != '\0') {
8951 9100 (void) strlcat(kernbuf, " ", sizeof (kernbuf));
8952 9101 (void) strlcat(kernbuf, args_buf,
8953 9102 sizeof (kernbuf));
8954 9103 }
8955 9104 }
8956 9105 BAM_DPRINTF(("%s: reboot with args, abspath specified: "
8957 9106 "kern=%s\n", fcn, kernbuf));
8958 9107 } else {
8959 9108 /*
8960 9109 * It may be a partial path, or it may be a partial
8961 9110 * path followed by options. Assume that only options
8962 9111 * follow a space. If someone sends us a kernel path
8963 9112 * that includes a space, they deserve to be broken.
8964 9113 */
8965 9114 opt_ptr = strchr(opt, ' ');
8966 9115 if (opt_ptr != NULL) {
8967 9116 *opt_ptr = '\0';
8968 9117 }
8969 9118
8970 9119 path = expand_path(opt);
8971 9120 if (path != NULL) {
8972 9121 (void) strlcpy(kernbuf, path, sizeof (kernbuf));
8973 9122 free(path);
8974 9123
8975 9124 /*
8976 9125 * If there were options given, use those.
8977 9126 * Otherwise, copy over the default options.
8978 9127 */
8979 9128 if (opt_ptr != NULL) {
8980 9129 /* Restore the space in opt string */
8981 9130 *opt_ptr = ' ';
8982 9131 (void) strlcat(kernbuf, opt_ptr,
8983 9132 sizeof (kernbuf));
8984 9133 } else {
8985 9134 ret = get_kernel(mp, ARGS_CMD, args_buf,
8986 9135 sizeof (args_buf));
8987 9136 INJECT_ERROR1("UPDATE_TEMP_PARTIAL_ARGS",
8988 9137 ret = BAM_ERROR);
8989 9138 if (ret != BAM_SUCCESS) {
8990 9139 free(fstype);
8991 9140 bam_error(_("reboot with arguments: "
8992 9141 "error querying current boot-args "
8993 9142 "settings\n"));
8994 9143 return (BAM_ERROR);
8995 9144 }
8996 9145
8997 9146 if (args_buf[0] != '\0') {
8998 9147 (void) strlcat(kernbuf, " ",
8999 9148 sizeof (kernbuf));
9000 9149 (void) strlcat(kernbuf,
9001 9150 args_buf, sizeof (kernbuf));
9002 9151 }
9003 9152 }
9004 9153 BAM_DPRINTF(("%s: resolved partial path: %s\n",
9005 9154 fcn, kernbuf));
9006 9155 } else {
9007 9156 free(fstype);
9008 9157 bam_error(_("unable to expand %s to a full file"
9009 9158 " path.\n"), opt);
9010 9159 bam_print_stderr(_("Rebooting with default kernel "
9011 9160 "and options.\n"));
9012 9161 return (BAM_ERROR);
9013 9162 }
9014 9163 }
9015 9164 free(fstype);
9016 9165 entry = add_boot_entry(mp, REBOOT_TITLE, signbuf, kernbuf,
9017 9166 NULL, NULL, NULL);
9018 9167 INJECT_ERROR1("REBOOT_ADD_BOOT_ENTRY", entry = BAM_ERROR);
9019 9168 if (entry == BAM_ERROR) {
9020 9169 bam_error(_("Cannot update menu. Cannot reboot with "
9021 9170 "requested arguments\n"));
9022 9171 return (BAM_ERROR);
9023 9172 }
9024 9173
9025 9174 save_default_entry(mp, BAM_OLDDEF);
9026 9175 ret = set_global(mp, menu_cmds[DEFAULT_CMD], entry);
9027 9176 INJECT_ERROR1("REBOOT_SET_GLOBAL", ret = BAM_ERROR);
9028 9177 if (ret == BAM_ERROR) {
9029 9178 bam_error(_("reboot with arguments: setting GRUB menu default "
9030 9179 "to %d failed\n"), entry);
9031 9180 }
9032 9181 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
9033 9182 return (BAM_WRITE);
9034 9183 }
9035 9184
9036 9185 error_t
9037 9186 set_global(menu_t *mp, char *globalcmd, int val)
9038 9187 {
9039 9188 line_t *lp;
9040 9189 line_t *found;
9041 9190 line_t *last;
9042 9191 char *cp;
9043 9192 char *str;
9044 9193 char prefix[BAM_MAXLINE];
9045 9194 size_t len;
9046 9195 const char *fcn = "set_global()";
9047 9196
9048 9197 assert(mp);
9049 9198 assert(globalcmd);
9050 9199
9051 9200 if (strcmp(globalcmd, menu_cmds[DEFAULT_CMD]) == 0) {
9052 9201 INJECT_ERROR1("SET_GLOBAL_VAL_NEG", val = -1);
9053 9202 INJECT_ERROR1("SET_GLOBAL_MENU_EMPTY", mp->end = NULL);
9054 9203 INJECT_ERROR1("SET_GLOBAL_VAL_TOO_BIG", val = 100);
9055 9204 if (val < 0 || mp->end == NULL || val > mp->end->entryNum) {
9056 9205 (void) snprintf(prefix, sizeof (prefix), "%d", val);
9057 9206 bam_error(_("invalid boot entry number: %s\n"), prefix);
9058 9207 return (BAM_ERROR);
9059 9208 }
9060 9209 }
9061 9210
9062 9211 found = last = NULL;
9063 9212 for (lp = mp->start; lp; lp = lp->next) {
9064 9213 if (lp->flags != BAM_GLOBAL)
9065 9214 continue;
9066 9215
9067 9216 last = lp; /* track the last global found */
9068 9217
9069 9218 INJECT_ERROR1("SET_GLOBAL_NULL_CMD", lp->cmd = NULL);
9070 9219 if (lp->cmd == NULL) {
9071 9220 bam_error(_("no command at line %d\n"), lp->lineNum);
9072 9221 continue;
9073 9222 }
9074 9223 if (strcmp(globalcmd, lp->cmd) != 0)
9075 9224 continue;
9076 9225
9077 9226 BAM_DPRINTF(("%s: found matching global command: %s\n",
9078 9227 fcn, globalcmd));
9079 9228
9080 9229 if (found) {
9081 9230 bam_error(_("duplicate command %s at line %d of "
9082 9231 "%sboot/grub/menu.lst\n"), globalcmd,
9083 9232 lp->lineNum, bam_root);
9084 9233 }
9085 9234 found = lp;
9086 9235 }
9087 9236
9088 9237 if (found == NULL) {
9089 9238 lp = s_calloc(1, sizeof (line_t));
9090 9239 if (last == NULL) {
9091 9240 lp->next = mp->start;
9092 9241 mp->start = lp;
9093 9242 mp->end = (mp->end) ? mp->end : lp;
9094 9243 } else {
9095 9244 lp->next = last->next;
9096 9245 last->next = lp;
9097 9246 if (lp->next == NULL)
9098 9247 mp->end = lp;
9099 9248 }
9100 9249 lp->flags = BAM_GLOBAL; /* other fields not needed for writes */
9101 9250 len = strlen(globalcmd) + strlen(menu_cmds[SEP_CMD]);
9102 9251 len += 10; /* val < 10 digits */
9103 9252 lp->line = s_calloc(1, len);
9104 9253 (void) snprintf(lp->line, len, "%s%s%d",
9105 9254 globalcmd, menu_cmds[SEP_CMD], val);
9106 9255 BAM_DPRINTF(("%s: wrote new global line: %s\n", fcn, lp->line));
9107 9256 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
9108 9257 return (BAM_WRITE);
9109 9258 }
9110 9259
9111 9260 /*
9112 9261 * We are changing an existing entry. Retain any prefix whitespace,
9113 9262 * but overwrite everything else. This preserves tabs added for
9114 9263 * readability.
9115 9264 */
9116 9265 str = found->line;
9117 9266 cp = prefix;
9118 9267 while (*str == ' ' || *str == '\t')
9119 9268 *(cp++) = *(str++);
9120 9269 *cp = '\0'; /* Terminate prefix */
9121 9270 len = strlen(prefix) + strlen(globalcmd);
9122 9271 len += strlen(menu_cmds[SEP_CMD]) + 10;
9123 9272
9124 9273 free(found->line);
9125 9274 found->line = s_calloc(1, len);
9126 9275 (void) snprintf(found->line, len,
9127 9276 "%s%s%s%d", prefix, globalcmd, menu_cmds[SEP_CMD], val);
9128 9277
9129 9278 BAM_DPRINTF(("%s: replaced global line with: %s\n", fcn, found->line));
9130 9279 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
9131 9280 return (BAM_WRITE); /* need a write to menu */
9132 9281 }
9133 9282
9134 9283 /*
9135 9284 * partial_path may be anything like "kernel/unix" or "kmdb". Try to
9136 9285 * expand it to a full unix path. The calling function is expected to
9137 9286 * output a message if an error occurs and NULL is returned.
9138 9287 */
9139 9288 static char *
9140 9289 expand_path(const char *partial_path)
9141 9290 {
9142 9291 int new_path_len;
9143 9292 char *new_path;
9144 9293 char new_path2[PATH_MAX];
9145 9294 struct stat sb;
9146 9295 const char *fcn = "expand_path()";
9147 9296
9148 9297 new_path_len = strlen(partial_path) + 64;
9149 9298 new_path = s_calloc(1, new_path_len);
9150 9299
9151 9300 /* First, try the simplest case - something like "kernel/unix" */
9152 9301 (void) snprintf(new_path, new_path_len, "/platform/i86pc/%s",
9153 9302 partial_path);
9154 9303 if (stat(new_path, &sb) == 0) {
9155 9304 BAM_DPRINTF(("%s: expanded path: %s\n", fcn, new_path));
9156 9305 return (new_path);
9157 9306 }
9158 9307
9159 9308 if (strcmp(partial_path, "kmdb") == 0) {
9160 9309 (void) snprintf(new_path, new_path_len, "%s -k",
9161 9310 DIRECT_BOOT_KERNEL);
9162 9311 BAM_DPRINTF(("%s: expanded path: %s\n", fcn, new_path));
9163 9312 return (new_path);
9164 9313 }
9165 9314
9166 9315 /*
9167 9316 * We've quickly reached unsupported usage. Try once more to
9168 9317 * see if we were just given a glom name.
9169 9318 */
9170 9319 (void) snprintf(new_path, new_path_len, "/platform/i86pc/%s/unix",
9171 9320 partial_path);
9172 9321 (void) snprintf(new_path2, PATH_MAX, "/platform/i86pc/%s/amd64/unix",
9173 9322 partial_path);
9174 9323 if (stat(new_path, &sb) == 0) {
9175 9324 if (stat(new_path2, &sb) == 0) {
9176 9325 /*
9177 9326 * We matched both, so we actually
9178 9327 * want to write the $ISADIR version.
9179 9328 */
9180 9329 (void) snprintf(new_path, new_path_len,
9181 9330 "/platform/i86pc/kernel/%s/$ISADIR/unix",
9182 9331 partial_path);
9183 9332 }
9184 9333 BAM_DPRINTF(("%s: expanded path: %s\n", fcn, new_path));
9185 9334 return (new_path);
9186 9335 }
9187 9336
9188 9337 free(new_path);
9189 9338 BAM_DPRINTF(("%s: returning FAILURE\n", fcn));
9190 9339 return (NULL);
9191 9340 }
9192 9341
9193 9342 /*
9194 9343 * The kernel cmd and arg have been changed, so
9195 9344 * check whether the archive line needs to change.
9196 9345 */
9197 9346 static void
9198 9347 set_archive_line(entry_t *entryp, line_t *kernelp)
9199 9348 {
9200 9349 line_t *lp = entryp->start;
9201 9350 char *new_archive;
9202 9351 menu_cmd_t m_cmd;
9203 9352 const char *fcn = "set_archive_line()";
9204 9353
9205 9354 for (; lp != NULL; lp = lp->next) {
9206 9355 if (lp->cmd != NULL && strncmp(lp->cmd, menu_cmds[MODULE_CMD],
9207 9356 sizeof (menu_cmds[MODULE_CMD]) - 1) == 0) {
9208 9357 break;
9209 9358 }
9210 9359
9211 9360 INJECT_ERROR1("SET_ARCHIVE_LINE_END_ENTRY", lp = entryp->end);
9212 9361 if (lp == entryp->end) {
9213 9362 BAM_DPRINTF(("%s: no module/archive line for entry: "
9214 9363 "%d\n", fcn, entryp->entryNum));
9215 9364 return;
9216 9365 }
9217 9366 }
9218 9367 INJECT_ERROR1("SET_ARCHIVE_LINE_END_MENU", lp = NULL);
9219 9368 if (lp == NULL) {
9220 9369 BAM_DPRINTF(("%s: no module/archive line for entry: %d\n",
9221 9370 fcn, entryp->entryNum));
9222 9371 return;
9223 9372 }
9224 9373
9225 9374 if (strstr(kernelp->arg, "$ISADIR") != NULL) {
9226 9375 new_archive = DIRECT_BOOT_ARCHIVE;
9227 9376 m_cmd = MODULE_DOLLAR_CMD;
9228 9377 } else if (strstr(kernelp->arg, "amd64") != NULL) {
9229 9378 new_archive = DIRECT_BOOT_ARCHIVE_64;
9230 9379 m_cmd = MODULE_CMD;
9231 9380 } else {
9232 9381 new_archive = DIRECT_BOOT_ARCHIVE_32;
9233 9382 m_cmd = MODULE_CMD;
9234 9383 }
9235 9384
9236 9385 if (strcmp(lp->arg, new_archive) == 0) {
9237 9386 BAM_DPRINTF(("%s: no change for line: %s\n", fcn, lp->arg));
9238 9387 return;
9239 9388 }
9240 9389
9241 9390 if (lp->cmd != NULL && strcmp(lp->cmd, menu_cmds[m_cmd]) != 0) {
9242 9391 free(lp->cmd);
9243 9392 lp->cmd = s_strdup(menu_cmds[m_cmd]);
9244 9393 }
9245 9394
9246 9395 free(lp->arg);
9247 9396 lp->arg = s_strdup(new_archive);
9248 9397 update_line(lp);
9249 9398 BAM_DPRINTF(("%s: replaced for line: %s\n", fcn, lp->line));
9250 9399 }
9251 9400
9252 9401 /*
9253 9402 * Title for an entry to set properties that once went in bootenv.rc.
9254 9403 */
9255 9404 #define BOOTENV_RC_TITLE "Solaris bootenv rc"
9256 9405
9257 9406 /*
9258 9407 * If path is NULL, return the kernel (optnum == KERNEL_CMD) or arguments
9259 9408 * (optnum == ARGS_CMD) in the argument buf. If path is a zero-length
9260 9409 * string, reset the value to the default. If path is a non-zero-length
9261 9410 * string, set the kernel or arguments.
9262 9411 */
9263 9412 static error_t
9264 9413 get_set_kernel(
9265 9414 menu_t *mp,
9266 9415 menu_cmd_t optnum,
9267 9416 char *path,
9268 9417 char *buf,
9269 9418 size_t bufsize)
9270 9419 {
9271 9420 int entryNum;
9272 9421 int rv = BAM_SUCCESS;
9273 9422 int free_new_path = 0;
9274 9423 entry_t *entryp;
9275 9424 line_t *ptr;
9276 9425 line_t *kernelp;
9277 9426 char *new_arg;
9278 9427 char *old_args;
9279 9428 char *space;
9280 9429 char *new_path;
9281 9430 char old_space;
9282 9431 size_t old_kernel_len = 0;
9283 9432 size_t new_str_len;
9284 9433 char *fstype;
9285 9434 char *osdev;
9286 9435 char *sign;
9287 9436 char signbuf[PATH_MAX];
9288 9437 int ret;
9289 9438 const char *fcn = "get_set_kernel()";
9290 9439
9291 9440 assert(bufsize > 0);
9292 9441
9293 9442 ptr = kernelp = NULL;
9294 9443 new_arg = old_args = space = NULL;
9295 9444 new_path = NULL;
9296 9445 buf[0] = '\0';
9297 9446
9298 9447 INJECT_ERROR1("GET_SET_KERNEL_NOT_DBOOT",
9299 9448 bam_direct = BAM_DIRECT_MULTIBOOT);
9300 9449 if (bam_direct != BAM_DIRECT_DBOOT) {
9301 9450 bam_error(_("bootadm set-menu %s may only be run on "
9302 9451 "directboot kernels.\n"),
9303 9452 optnum == KERNEL_CMD ? "kernel" : "args");
9304 9453 return (BAM_ERROR);
9305 9454 }
9306 9455
9307 9456 /*
9308 9457 * If a user changed the default entry to a non-bootadm controlled
9309 9458 * one, we don't want to mess with it. Just print an error and
9310 9459 * return.
9311 9460 */
9312 9461 if (mp->curdefault) {
9313 9462 entryNum = s_strtol(mp->curdefault->arg);
9314 9463 for (entryp = mp->entries; entryp; entryp = entryp->next) {
9315 9464 if (entryp->entryNum == entryNum)
9316 9465 break;
9317 9466 }
9318 9467 if ((entryp != NULL) &&
9319 9468 ((entryp->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU)) == 0)) {
9320 9469 bam_error(_("Default /boot/grub/menu.lst entry is not "
9321 9470 "controlled by bootadm. Exiting\n"));
9322 9471 return (BAM_ERROR);
9323 9472 }
9324 9473 }
9325 9474
9326 9475 entryp = find_boot_entry(mp, BOOTENV_RC_TITLE, NULL, NULL, NULL, NULL,
9327 9476 0, &entryNum);
9328 9477
9329 9478 if (entryp != NULL) {
9330 9479 for (ptr = entryp->start; ptr && ptr != entryp->end;
9331 9480 ptr = ptr->next) {
9332 9481 if (strncmp(ptr->cmd, menu_cmds[KERNEL_CMD],
9333 9482 sizeof (menu_cmds[KERNEL_CMD]) - 1) == 0) {
9334 9483 kernelp = ptr;
9335 9484 break;
9336 9485 }
9337 9486 }
9338 9487 if (kernelp == NULL) {
9339 9488 bam_error(_("no kernel line found in entry %d\n"),
9340 9489 entryNum);
9341 9490 return (BAM_ERROR);
9342 9491 }
9343 9492
9344 9493 old_kernel_len = strcspn(kernelp->arg, " \t");
9345 9494 space = old_args = kernelp->arg + old_kernel_len;
9346 9495 while ((*old_args == ' ') || (*old_args == '\t'))
9347 9496 old_args++;
9348 9497 }
9349 9498
9350 9499 if (path == NULL) {
9351 9500 if (entryp == NULL) {
9352 9501 BAM_DPRINTF(("%s: no RC entry, nothing to report\n",
9353 9502 fcn));
9354 9503 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
9355 9504 return (BAM_SUCCESS);
9356 9505 }
9357 9506 assert(kernelp);
9358 9507 if (optnum == ARGS_CMD) {
9359 9508 if (old_args[0] != '\0') {
9360 9509 (void) strlcpy(buf, old_args, bufsize);
9361 9510 BAM_DPRINTF(("%s: read menu boot-args: %s\n",
9362 9511 fcn, buf));
9363 9512 }
9364 9513 } else {
9365 9514 /*
9366 9515 * We need to print the kernel, so we just turn the
9367 9516 * first space into a '\0' and print the beginning.
9368 9517 * We don't print anything if it's the default kernel.
9369 9518 */
9370 9519 old_space = *space;
9371 9520 *space = '\0';
9372 9521 if (strcmp(kernelp->arg, DIRECT_BOOT_KERNEL) != 0) {
9373 9522 (void) strlcpy(buf, kernelp->arg, bufsize);
9374 9523 BAM_DPRINTF(("%s: read menu boot-file: %s\n",
9375 9524 fcn, buf));
9376 9525 }
9377 9526 *space = old_space;
9378 9527 }
9379 9528 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
9380 9529 return (BAM_SUCCESS);
9381 9530 }
9382 9531
9383 9532 /*
9384 9533 * First, check if we're resetting an entry to the default.
9385 9534 */
9386 9535 if ((path[0] == '\0') ||
9387 9536 ((optnum == KERNEL_CMD) &&
9388 9537 (strcmp(path, DIRECT_BOOT_KERNEL) == 0))) {
9389 9538 if ((entryp == NULL) || (kernelp == NULL)) {
9390 9539 /* No previous entry, it's already the default */
9391 9540 BAM_DPRINTF(("%s: no reset, already has default\n",
9392 9541 fcn));
9393 9542 return (BAM_SUCCESS);
9394 9543 }
9395 9544
9396 9545 /*
9397 9546 * Check if we can delete the entry. If we're resetting the
9398 9547 * kernel command, and the args is already empty, or if we're
9399 9548 * resetting the args command, and the kernel is already the
9400 9549 * default, we can restore the old default and delete the entry.
9401 9550 */
9402 9551 if (((optnum == KERNEL_CMD) &&
9403 9552 ((old_args == NULL) || (old_args[0] == '\0'))) ||
9404 9553 ((optnum == ARGS_CMD) &&
9405 9554 (strncmp(kernelp->arg, DIRECT_BOOT_KERNEL,
9406 9555 sizeof (DIRECT_BOOT_KERNEL) - 1) == 0))) {
9407 9556 kernelp = NULL;
9408 9557 (void) delete_boot_entry(mp, entryNum, DBE_PRINTERR);
9409 9558 restore_default_entry(mp, BAM_OLD_RC_DEF,
9410 9559 mp->old_rc_default);
9411 9560 mp->old_rc_default = NULL;
9412 9561 rv = BAM_WRITE;
9413 9562 BAM_DPRINTF(("%s: resetting to default\n", fcn));
9414 9563 goto done;
9415 9564 }
9416 9565
9417 9566 if (optnum == KERNEL_CMD) {
9418 9567 /*
9419 9568 * At this point, we've already checked that old_args
9420 9569 * and entryp are valid pointers. The "+ 2" is for
9421 9570 * a space a the string termination character.
9422 9571 */
9423 9572 new_str_len = (sizeof (DIRECT_BOOT_KERNEL) - 1) +
9424 9573 strlen(old_args) + 2;
9425 9574 new_arg = s_calloc(1, new_str_len);
9426 9575 (void) snprintf(new_arg, new_str_len, "%s %s",
9427 9576 DIRECT_BOOT_KERNEL, old_args);
9428 9577 free(kernelp->arg);
9429 9578 kernelp->arg = new_arg;
9430 9579
9431 9580 /*
9432 9581 * We have changed the kernel line, so we may need
9433 9582 * to update the archive line as well.
9434 9583 */
9435 9584 set_archive_line(entryp, kernelp);
9436 9585 BAM_DPRINTF(("%s: reset kernel to default, but "
9437 9586 "retained old args: %s\n", fcn, kernelp->arg));
9438 9587 } else {
9439 9588 /*
9440 9589 * We're resetting the boot args to nothing, so
9441 9590 * we only need to copy the kernel. We've already
9442 9591 * checked that the kernel is not the default.
9443 9592 */
9444 9593 new_arg = s_calloc(1, old_kernel_len + 1);
9445 9594 (void) snprintf(new_arg, old_kernel_len + 1, "%s",
9446 9595 kernelp->arg);
9447 9596 free(kernelp->arg);
9448 9597 kernelp->arg = new_arg;
9449 9598 BAM_DPRINTF(("%s: reset args to default, but retained "
9450 9599 "old kernel: %s\n", fcn, kernelp->arg));
9451 9600 }
9452 9601 rv = BAM_WRITE;
9453 9602 goto done;
9454 9603 }
9455 9604
9456 9605 /*
9457 9606 * Expand the kernel file to a full path, if necessary
9458 9607 */
9459 9608 if ((optnum == KERNEL_CMD) && (path[0] != '/')) {
9460 9609 new_path = expand_path(path);
9461 9610 if (new_path == NULL) {
9462 9611 bam_error(_("unable to expand %s to a full file "
9463 9612 "path.\n"), path);
9464 9613 BAM_DPRINTF(("%s: returning FAILURE\n", fcn));
9465 9614 return (BAM_ERROR);
9466 9615 }
9467 9616 free_new_path = 1;
9468 9617 } else {
9469 9618 new_path = path;
9470 9619 free_new_path = 0;
9471 9620 }
9472 9621
9473 9622 /*
9474 9623 * At this point, we know we're setting a new value. First, take care
9475 9624 * of the case where there was no previous entry.
9476 9625 */
9477 9626 if (entryp == NULL) {
9478 9627
9479 9628 /* Similar to code in update_temp */
9480 9629 fstype = get_fstype("/");
9481 9630 INJECT_ERROR1("GET_SET_KERNEL_FSTYPE", fstype = NULL);
9482 9631 if (fstype == NULL) {
9483 9632 bam_error(_("cannot determine filesystem type for "
9484 9633 "\"/\".\nCannot generate GRUB menu entry with "
9485 9634 "EEPROM arguments.\n"));
9486 9635 rv = BAM_ERROR;
9487 9636 goto done;
9488 9637 }
9489 9638
9490 9639 osdev = get_special("/");
9491 9640 INJECT_ERROR1("GET_SET_KERNEL_SPECIAL", osdev = NULL);
9492 9641 if (osdev == NULL) {
9493 9642 free(fstype);
9494 9643 bam_error(_("cannot determine device special file for "
9495 9644 "\"/\".\nCannot generate GRUB menu entry with "
9496 9645 "EEPROM arguments.\n"));
9497 9646 rv = BAM_ERROR;
9498 9647 goto done;
9499 9648 }
9500 9649
9501 9650 sign = find_existing_sign("/", osdev, fstype);
9502 9651 INJECT_ERROR1("GET_SET_KERNEL_SIGN", sign = NULL);
9503 9652 if (sign == NULL) {
9504 9653 free(fstype);
9505 9654 free(osdev);
9506 9655 bam_error(_("cannot determine boot signature for "
9507 9656 "\"/\".\nCannot generate GRUB menu entry with "
9508 9657 "EEPROM arguments.\n"));
9509 9658 rv = BAM_ERROR;
9510 9659 goto done;
9511 9660 }
9512 9661
9513 9662 free(osdev);
9514 9663 (void) strlcpy(signbuf, sign, sizeof (signbuf));
9515 9664 free(sign);
9516 9665 assert(strchr(signbuf, '(') == NULL &&
9517 9666 strchr(signbuf, ',') == NULL &&
9518 9667 strchr(signbuf, ')') == NULL);
9519 9668
9520 9669 if (optnum == KERNEL_CMD) {
9521 9670 if (strcmp(fstype, "zfs") == 0) {
9522 9671 new_str_len = strlen(new_path) +
9523 9672 strlen(ZFS_BOOT) + 8;
9524 9673 new_arg = s_calloc(1, new_str_len);
9525 9674 (void) snprintf(new_arg, new_str_len, "%s %s",
9526 9675 new_path, ZFS_BOOT);
9527 9676 BAM_DPRINTF(("%s: new kernel=%s\n", fcn,
9528 9677 new_arg));
9529 9678 entryNum = add_boot_entry(mp, BOOTENV_RC_TITLE,
9530 9679 signbuf, new_arg, NULL, NULL, NULL);
9531 9680 free(new_arg);
9532 9681 } else {
9533 9682 BAM_DPRINTF(("%s: new kernel=%s\n", fcn,
9534 9683 new_path));
9535 9684 entryNum = add_boot_entry(mp, BOOTENV_RC_TITLE,
9536 9685 signbuf, new_path, NULL, NULL, NULL);
9537 9686 }
9538 9687 } else {
9539 9688 new_str_len = strlen(path) + 8;
9540 9689 if (strcmp(fstype, "zfs") == 0) {
9541 9690 new_str_len += strlen(DIRECT_BOOT_KERNEL_ZFS);
9542 9691 new_arg = s_calloc(1, new_str_len);
9543 9692 (void) snprintf(new_arg, new_str_len, "%s %s",
9544 9693 DIRECT_BOOT_KERNEL_ZFS, path);
9545 9694 } else {
9546 9695 new_str_len += strlen(DIRECT_BOOT_KERNEL);
9547 9696 new_arg = s_calloc(1, new_str_len);
9548 9697 (void) snprintf(new_arg, new_str_len, "%s %s",
9549 9698 DIRECT_BOOT_KERNEL, path);
9550 9699 }
9551 9700
9552 9701 BAM_DPRINTF(("%s: new args=%s\n", fcn, new_arg));
9553 9702 entryNum = add_boot_entry(mp, BOOTENV_RC_TITLE,
9554 9703 signbuf, new_arg, NULL, DIRECT_BOOT_ARCHIVE, NULL);
9555 9704 free(new_arg);
9556 9705 }
9557 9706 free(fstype);
9558 9707 INJECT_ERROR1("GET_SET_KERNEL_ADD_BOOT_ENTRY",
9559 9708 entryNum = BAM_ERROR);
9560 9709 if (entryNum == BAM_ERROR) {
9561 9710 bam_error(_("failed to add boot entry: %s\n"),
9562 9711 BOOTENV_RC_TITLE);
9563 9712 rv = BAM_ERROR;
9564 9713 goto done;
9565 9714 }
9566 9715 save_default_entry(mp, BAM_OLD_RC_DEF);
9567 9716 ret = set_global(mp, menu_cmds[DEFAULT_CMD], entryNum);
9568 9717 INJECT_ERROR1("GET_SET_KERNEL_SET_GLOBAL", ret = BAM_ERROR);
9569 9718 if (ret == BAM_ERROR) {
9570 9719 bam_error(_("failed to set default to: %d\n"),
9571 9720 entryNum);
9572 9721 }
9573 9722 rv = BAM_WRITE;
9574 9723 goto done;
9575 9724 }
9576 9725
9577 9726 /*
9578 9727 * There was already an bootenv entry which we need to edit.
9579 9728 */
9580 9729 if (optnum == KERNEL_CMD) {
9581 9730 new_str_len = strlen(new_path) + strlen(old_args) + 2;
9582 9731 new_arg = s_calloc(1, new_str_len);
9583 9732 (void) snprintf(new_arg, new_str_len, "%s %s", new_path,
9584 9733 old_args);
9585 9734 free(kernelp->arg);
9586 9735 kernelp->arg = new_arg;
9587 9736
9588 9737 /*
9589 9738 * If we have changed the kernel line, we may need to update
9590 9739 * the archive line as well.
9591 9740 */
9592 9741 set_archive_line(entryp, kernelp);
9593 9742 BAM_DPRINTF(("%s: rc line exists, replaced kernel, same "
9594 9743 "args: %s\n", fcn, kernelp->arg));
9595 9744 } else {
9596 9745 new_str_len = old_kernel_len + strlen(path) + 8;
9597 9746 new_arg = s_calloc(1, new_str_len);
9598 9747 (void) strncpy(new_arg, kernelp->arg, old_kernel_len);
9599 9748 (void) strlcat(new_arg, " ", new_str_len);
9600 9749 (void) strlcat(new_arg, path, new_str_len);
9601 9750 free(kernelp->arg);
9602 9751 kernelp->arg = new_arg;
9603 9752 BAM_DPRINTF(("%s: rc line exists, same kernel, but new "
9604 9753 "args: %s\n", fcn, kernelp->arg));
9605 9754 }
9606 9755 rv = BAM_WRITE;
9607 9756
9608 9757 done:
9609 9758 if ((rv == BAM_WRITE) && kernelp)
9610 9759 update_line(kernelp);
9611 9760 if (free_new_path)
9612 9761 free(new_path);
9613 9762 if (rv == BAM_WRITE) {
9614 9763 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
9615 9764 } else {
9616 9765 BAM_DPRINTF(("%s: returning FAILURE\n", fcn));
9617 9766 }
9618 9767 return (rv);
9619 9768 }
9620 9769
9621 9770 static error_t
9622 9771 get_kernel(menu_t *mp, menu_cmd_t optnum, char *buf, size_t bufsize)
9623 9772 {
9624 9773 const char *fcn = "get_kernel()";
9625 9774 BAM_DPRINTF(("%s: entered. arg: %s\n", fcn, menu_cmds[optnum]));
9626 9775 return (get_set_kernel(mp, optnum, NULL, buf, bufsize));
9627 9776 }
9628 9777
9629 9778 static error_t
9630 9779 set_kernel(menu_t *mp, menu_cmd_t optnum, char *path, char *buf, size_t bufsize)
9631 9780 {
9632 9781 const char *fcn = "set_kernel()";
9633 9782 assert(path != NULL);
9634 9783 BAM_DPRINTF(("%s: entered. args: %s %s\n", fcn,
9635 9784 menu_cmds[optnum], path));
9636 9785 return (get_set_kernel(mp, optnum, path, buf, bufsize));
9637 9786 }
9638 9787
9639 9788 /*ARGSUSED*/
9640 9789 static error_t
9641 9790 set_option(menu_t *mp, char *dummy, char *opt)
9642 9791 {
9643 9792 int optnum;
9644 9793 int optval;
9645 9794 char *val;
9646 9795 char buf[BUFSIZ] = "";
9647 9796 error_t rv;
9648 9797 const char *fcn = "set_option()";
9649 9798
9650 9799 assert(mp);
9651 9800 assert(opt);
9652 9801 assert(dummy == NULL);
9653 9802
9654 9803 /* opt is set from bam_argv[0] and is always non-NULL */
9655 9804 BAM_DPRINTF(("%s: entered. arg: %s\n", fcn, opt));
9656 9805
9657 9806 val = strchr(opt, '=');
9658 9807 if (val != NULL) {
9659 9808 *val = '\0';
9660 9809 }
9661 9810
9662 9811 if (strcmp(opt, "default") == 0) {
9663 9812 optnum = DEFAULT_CMD;
9664 9813 } else if (strcmp(opt, "timeout") == 0) {
9665 9814 optnum = TIMEOUT_CMD;
9666 9815 } else if (strcmp(opt, menu_cmds[KERNEL_CMD]) == 0) {
9667 9816 optnum = KERNEL_CMD;
9668 9817 } else if (strcmp(opt, menu_cmds[ARGS_CMD]) == 0) {
9669 9818 optnum = ARGS_CMD;
9670 9819 } else {
9671 9820 bam_error(_("invalid option: %s\n"), opt);
9672 9821 return (BAM_ERROR);
9673 9822 }
9674 9823
9675 9824 /*
9676 9825 * kernel and args are allowed without "=new_value" strings. All
9677 9826 * others cause errors
9678 9827 */
9679 9828 if ((val == NULL) && (optnum != KERNEL_CMD) && (optnum != ARGS_CMD)) {
9680 9829 bam_error(_("option has no argument: %s\n"), opt);
9681 9830 return (BAM_ERROR);
9682 9831 } else if (val != NULL) {
9683 9832 *val = '=';
9684 9833 }
9685 9834
9686 9835 if ((optnum == KERNEL_CMD) || (optnum == ARGS_CMD)) {
9687 9836 BAM_DPRINTF(("%s: setting %s option to %s\n",
9688 9837 fcn, menu_cmds[optnum], val ? val + 1 : "NULL"));
9689 9838
9690 9839 if (val)
9691 9840 rv = set_kernel(mp, optnum, val + 1, buf, sizeof (buf));
9692 9841 else
9693 9842 rv = get_kernel(mp, optnum, buf, sizeof (buf));
9694 9843 if ((rv == BAM_SUCCESS) && (buf[0] != '\0'))
9695 9844 (void) printf("%s\n", buf);
9696 9845 } else {
9697 9846 optval = s_strtol(val + 1);
9698 9847 BAM_DPRINTF(("%s: setting %s option to %s\n", fcn,
9699 9848 menu_cmds[optnum], val + 1));
9700 9849 rv = set_global(mp, menu_cmds[optnum], optval);
9701 9850 }
9702 9851
9703 9852 if (rv == BAM_WRITE || rv == BAM_SUCCESS) {
9704 9853 BAM_DPRINTF(("%s: returning SUCCESS\n", fcn));
9705 9854 } else {
9706 9855 BAM_DPRINTF(("%s: returning FAILURE\n", fcn));
9707 9856 }
9708 9857
9709 9858 return (rv);
9710 9859 }
9711 9860
9712 9861 /*
9713 9862 * The quiet argument suppresses messages. This is used
9714 9863 * when invoked in the context of other commands (e.g. list_entry)
9715 9864 */
9716 9865 static error_t
9717 9866 read_globals(menu_t *mp, char *menu_path, char *globalcmd, int quiet)
9718 9867 {
9719 9868 line_t *lp;
9720 9869 char *arg;
9721 9870 int done, ret = BAM_SUCCESS;
9722 9871
9723 9872 assert(mp);
9724 9873 assert(menu_path);
9725 9874 assert(globalcmd);
9726 9875
9727 9876 if (mp->start == NULL) {
9728 9877 if (!quiet)
9729 9878 bam_error(_("menu file not found: %s\n"), menu_path);
9730 9879 return (BAM_ERROR);
9731 9880 }
9732 9881
9733 9882 done = 0;
9734 9883 for (lp = mp->start; lp; lp = lp->next) {
9735 9884 if (lp->flags != BAM_GLOBAL)
9736 9885 continue;
9737 9886
9738 9887 if (lp->cmd == NULL) {
9739 9888 if (!quiet)
9740 9889 bam_error(_("no command at line %d\n"),
9741 9890 lp->lineNum);
9742 9891 continue;
9743 9892 }
9744 9893
9745 9894 if (strcmp(globalcmd, lp->cmd) != 0)
9746 9895 continue;
9747 9896
9748 9897 /* Found global. Check for duplicates */
9749 9898 if (done && !quiet) {
9750 9899 bam_error(_("duplicate command %s at line %d of "
9751 9900 "%sboot/grub/menu.lst\n"), globalcmd,
9752 9901 lp->lineNum, bam_root);
9753 9902 ret = BAM_ERROR;
9754 9903 }
9755 9904
9756 9905 arg = lp->arg ? lp->arg : "";
9757 9906 bam_print(_("%s %s\n"), globalcmd, arg);
9758 9907 done = 1;
9759 9908 }
9760 9909
9761 9910 if (!done && bam_verbose)
9762 9911 bam_print(_("no %s entry found\n"), globalcmd);
9763 9912
9764 9913 return (ret);
9765 9914 }
9766 9915
9767 9916 static error_t
9768 9917 menu_write(char *root, menu_t *mp)
9769 9918 {
9770 9919 const char *fcn = "menu_write()";
9771 9920
9772 9921 BAM_DPRINTF(("%s: entered menu_write() for root: <%s>\n", fcn, root));
9773 9922 return (list2file(root, MENU_TMP, GRUB_MENU, mp->start));
9774 9923 }
9775 9924
9776 9925 void
9777 9926 line_free(line_t *lp)
9778 9927 {
9779 9928 if (lp == NULL)
9780 9929 return;
9781 9930
9782 9931 if (lp->cmd != NULL)
9783 9932 free(lp->cmd);
9784 9933 if (lp->sep)
9785 9934 free(lp->sep);
9786 9935 if (lp->arg)
9787 9936 free(lp->arg);
9788 9937 if (lp->line)
9789 9938 free(lp->line);
9790 9939 free(lp);
9791 9940 }
9792 9941
9793 9942 static void
9794 9943 linelist_free(line_t *start)
9795 9944 {
9796 9945 line_t *lp;
9797 9946
9798 9947 while (start) {
9799 9948 lp = start;
9800 9949 start = start->next;
9801 9950 line_free(lp);
9802 9951 }
9803 9952 }
9804 9953
9805 9954 static void
9806 9955 filelist_free(filelist_t *flistp)
9807 9956 {
9808 9957 linelist_free(flistp->head);
9809 9958 flistp->head = NULL;
9810 9959 flistp->tail = NULL;
9811 9960 }
9812 9961
9813 9962 static void
9814 9963 menu_free(menu_t *mp)
9815 9964 {
9816 9965 entry_t *ent, *tmp;
9817 9966 assert(mp);
9818 9967
9819 9968 if (mp->start)
9820 9969 linelist_free(mp->start);
9821 9970 ent = mp->entries;
9822 9971 while (ent) {
9823 9972 tmp = ent;
9824 9973 ent = tmp->next;
9825 9974 free(tmp);
9826 9975 }
9827 9976
9828 9977 free(mp);
9829 9978 }
9830 9979
9831 9980 /*
9832 9981 * Utility routines
9833 9982 */
9834 9983
9835 9984
9836 9985 /*
9837 9986 * Returns 0 on success
9838 9987 * Any other value indicates an error
9839 9988 */
9840 9989 static int
9841 9990 exec_cmd(char *cmdline, filelist_t *flistp)
9842 9991 {
9843 9992 char buf[BUFSIZ];
9844 9993 int ret;
9845 9994 FILE *ptr;
9846 9995 sigset_t set;
9847 9996 void (*disp)(int);
9848 9997
9849 9998 /*
9850 9999 * For security
9851 10000 * - only absolute paths are allowed
9852 10001 * - set IFS to space and tab
9853 10002 */
9854 10003 if (*cmdline != '/') {
9855 10004 bam_error(_("path is not absolute: %s\n"), cmdline);
9856 10005 return (-1);
9857 10006 }
9858 10007 (void) putenv("IFS= \t");
9859 10008
9860 10009 /*
9861 10010 * We may have been exec'ed with SIGCHLD blocked
9862 10011 * unblock it here
9863 10012 */
9864 10013 (void) sigemptyset(&set);
9865 10014 (void) sigaddset(&set, SIGCHLD);
9866 10015 if (sigprocmask(SIG_UNBLOCK, &set, NULL) != 0) {
9867 10016 bam_error(_("cannot unblock SIGCHLD: %s\n"), strerror(errno));
9868 10017 return (-1);
9869 10018 }
9870 10019
9871 10020 /*
9872 10021 * Set SIGCHLD disposition to SIG_DFL for popen/pclose
9873 10022 */
9874 10023 disp = sigset(SIGCHLD, SIG_DFL);
9875 10024 if (disp == SIG_ERR) {
9876 10025 bam_error(_("cannot set SIGCHLD disposition: %s\n"),
9877 10026 strerror(errno));
9878 10027 return (-1);
9879 10028 }
9880 10029 if (disp == SIG_HOLD) {
9881 10030 bam_error(_("SIGCHLD signal blocked. Cannot exec: %s\n"),
9882 10031 cmdline);
9883 10032 return (-1);
9884 10033 }
9885 10034
9886 10035 ptr = popen(cmdline, "r");
9887 10036 if (ptr == NULL) {
9888 10037 bam_error(_("popen failed: %s: %s\n"), cmdline,
9889 10038 strerror(errno));
9890 10039 return (-1);
9891 10040 }
9892 10041
9893 10042 /*
9894 10043 * If we simply do a pclose() following a popen(), pclose()
9895 10044 * will close the reader end of the pipe immediately even
9896 10045 * if the child process has not started/exited. pclose()
9897 10046 * does wait for cmd to terminate before returning though.
9898 10047 * When the executed command writes its output to the pipe
9899 10048 * there is no reader process and the command dies with
9900 10049 * SIGPIPE. To avoid this we read repeatedly until read
9901 10050 * terminates with EOF. This indicates that the command
9902 10051 * (writer) has closed the pipe and we can safely do a
9903 10052 * pclose().
9904 10053 *
9905 10054 * Since pclose() does wait for the command to exit,
9906 10055 * we can safely reap the exit status of the command
9907 10056 * from the value returned by pclose()
9908 10057 */
9909 10058 while (s_fgets(buf, sizeof (buf), ptr) != NULL) {
9910 10059 if (flistp == NULL) {
9911 10060 /* s_fgets strips newlines, so insert them at the end */
9912 10061 bam_print(_("%s\n"), buf);
9913 10062 } else {
9914 10063 append_to_flist(flistp, buf);
9915 10064 }
9916 10065 }
9917 10066
9918 10067 ret = pclose(ptr);
9919 10068 if (ret == -1) {
9920 10069 bam_error(_("pclose failed: %s: %s\n"), cmdline,
9921 10070 strerror(errno));
9922 10071 return (-1);
9923 10072 }
9924 10073
9925 10074 if (WIFEXITED(ret)) {
9926 10075 return (WEXITSTATUS(ret));
9927 10076 } else {
9928 10077 bam_error(_("command terminated abnormally: %s: %d\n"),
9929 10078 cmdline, ret);
9930 10079 return (-1);
9931 10080 }
9932 10081 }
9933 10082
9934 10083 /*
9935 10084 * Since this function returns -1 on error
9936 10085 * it cannot be used to convert -1. However,
9937 10086 * that is sufficient for what we need.
9938 10087 */
9939 10088 static long
9940 10089 s_strtol(char *str)
9941 10090 {
9942 10091 long l;
9943 10092 char *res = NULL;
9944 10093
9945 10094 if (str == NULL) {
9946 10095 return (-1);
9947 10096 }
9948 10097
9949 10098 errno = 0;
9950 10099 l = strtol(str, &res, 10);
9951 10100 if (errno || *res != '\0') {
9952 10101 return (-1);
9953 10102 }
9954 10103
9955 10104 return (l);
9956 10105 }
9957 10106
9958 10107 /*
9959 10108 * Wrapper around fputs, that adds a newline (since fputs doesn't)
9960 10109 */
9961 10110 static int
9962 10111 s_fputs(char *str, FILE *fp)
9963 10112 {
9964 10113 char linebuf[BAM_MAXLINE];
9965 10114
9966 10115 (void) snprintf(linebuf, sizeof (linebuf), "%s\n", str);
9967 10116 return (fputs(linebuf, fp));
9968 10117 }
9969 10118
9970 10119 /*
9971 10120 * Wrapper around fgets, that strips newlines returned by fgets
9972 10121 */
9973 10122 char *
9974 10123 s_fgets(char *buf, int buflen, FILE *fp)
9975 10124 {
9976 10125 int n;
9977 10126
9978 10127 buf = fgets(buf, buflen, fp);
9979 10128 if (buf) {
9980 10129 n = strlen(buf);
9981 10130 if (n == buflen - 1 && buf[n-1] != '\n')
9982 10131 bam_error(_("the following line is too long "
9983 10132 "(> %d chars)\n\t%s\n"), buflen - 1, buf);
9984 10133 buf[n-1] = (buf[n-1] == '\n') ? '\0' : buf[n-1];
9985 10134 }
9986 10135
9987 10136 return (buf);
9988 10137 }
9989 10138
9990 10139 void *
9991 10140 s_calloc(size_t nelem, size_t sz)
9992 10141 {
9993 10142 void *ptr;
9994 10143
9995 10144 ptr = calloc(nelem, sz);
9996 10145 if (ptr == NULL) {
9997 10146 bam_error(_("could not allocate memory: size = %u\n"),
9998 10147 nelem*sz);
9999 10148 bam_exit(1);
10000 10149 }
10001 10150 return (ptr);
10002 10151 }
10003 10152
10004 10153 void *
10005 10154 s_realloc(void *ptr, size_t sz)
10006 10155 {
10007 10156 ptr = realloc(ptr, sz);
10008 10157 if (ptr == NULL) {
10009 10158 bam_error(_("could not allocate memory: size = %u\n"), sz);
10010 10159 bam_exit(1);
10011 10160 }
10012 10161 return (ptr);
10013 10162 }
10014 10163
10015 10164 char *
10016 10165 s_strdup(char *str)
10017 10166 {
10018 10167 char *ptr;
10019 10168
10020 10169 if (str == NULL)
10021 10170 return (NULL);
10022 10171
10023 10172 ptr = strdup(str);
10024 10173 if (ptr == NULL) {
10025 10174 bam_error(_("could not allocate memory: size = %u\n"),
10026 10175 strlen(str) + 1);
10027 10176 bam_exit(1);
10028 10177 }
10029 10178 return (ptr);
10030 10179 }
10031 10180
10032 10181 /*
10033 10182 * Returns 1 if amd64 (or sparc, for syncing x86 diskless clients)
10034 10183 * Returns 0 otherwise
10035 10184 */
10036 10185 static int
10037 10186 is_amd64(void)
10038 10187 {
10039 10188 static int amd64 = -1;
10040 10189 char isabuf[257]; /* from sysinfo(2) manpage */
10041 10190
10042 10191 if (amd64 != -1)
10043 10192 return (amd64);
10044 10193
10045 10194 if (bam_alt_platform) {
10046 10195 if (strcmp(bam_platform, "i86pc") == 0) {
10047 10196 amd64 = 1; /* diskless server */
10048 10197 }
10049 10198 } else {
10050 10199 if (sysinfo(SI_ISALIST, isabuf, sizeof (isabuf)) > 0 &&
10051 10200 strncmp(isabuf, "amd64 ", strlen("amd64 ")) == 0) {
10052 10201 amd64 = 1;
10053 10202 } else if (strstr(isabuf, "i386") == NULL) {
10054 10203 amd64 = 1; /* diskless server */
10055 10204 }
10056 10205 }
10057 10206 if (amd64 == -1)
10058 10207 amd64 = 0;
10059 10208
10060 10209 return (amd64);
10061 10210 }
10062 10211
10063 10212 static char *
10064 10213 get_machine(void)
10065 10214 {
10066 10215 static int cached = -1;
10067 10216 static char mbuf[257]; /* from sysinfo(2) manpage */
10068 10217
10069 10218 if (cached == 0)
10070 10219 return (mbuf);
10071 10220
10072 10221 if (bam_alt_platform) {
10073 10222 return (bam_platform);
10074 10223 } else {
10075 10224 if (sysinfo(SI_MACHINE, mbuf, sizeof (mbuf)) > 0) {
10076 10225 cached = 1;
10077 10226 }
10078 10227 }
10079 10228 if (cached == -1) {
10080 10229 mbuf[0] = '\0';
10081 10230 cached = 0;
10082 10231 }
10083 10232
10084 10233 return (mbuf);
10085 10234 }
10086 10235
10087 10236 int
10088 10237 is_sparc(void)
10089 10238 {
10090 10239 static int issparc = -1;
10091 10240 char mbuf[257]; /* from sysinfo(2) manpage */
10092 10241
10093 10242 if (issparc != -1)
10094 10243 return (issparc);
10095 10244
10096 10245 if (bam_alt_platform) {
10097 10246 if (strncmp(bam_platform, "sun4", 4) == 0) {
10098 10247 issparc = 1;
10099 10248 }
10100 10249 } else {
10101 10250 if (sysinfo(SI_ARCHITECTURE, mbuf, sizeof (mbuf)) > 0 &&
10102 10251 strcmp(mbuf, "sparc") == 0) {
10103 10252 issparc = 1;
10104 10253 }
10105 10254 }
10106 10255 if (issparc == -1)
10107 10256 issparc = 0;
10108 10257
10109 10258 return (issparc);
10110 10259 }
10111 10260
10112 10261 static void
10113 10262 append_to_flist(filelist_t *flistp, char *s)
10114 10263 {
10115 10264 line_t *lp;
10116 10265
10117 10266 lp = s_calloc(1, sizeof (line_t));
10118 10267 lp->line = s_strdup(s);
10119 10268 if (flistp->head == NULL)
10120 10269 flistp->head = lp;
10121 10270 else
10122 10271 flistp->tail->next = lp;
10123 10272 flistp->tail = lp;
10124 10273 }
10125 10274
10126 10275 #if !defined(_OBP)
10127 10276
10128 10277 UCODE_VENDORS;
10129 10278
10130 10279 /*ARGSUSED*/
10131 10280 static void
10132 10281 ucode_install(char *root)
10133 10282 {
10134 10283 int i;
10135 10284
10136 10285 for (i = 0; ucode_vendors[i].filestr != NULL; i++) {
10137 10286 int cmd_len = PATH_MAX + 256;
10138 10287 char cmd[PATH_MAX + 256];
10139 10288 char file[PATH_MAX];
10140 10289 char timestamp[PATH_MAX];
10141 10290 struct stat fstatus, tstatus;
10142 10291 struct utimbuf u_times;
10143 10292
10144 10293 (void) snprintf(file, PATH_MAX, "%s/%s/%s-ucode.%s",
10145 10294 bam_root, UCODE_INSTALL_PATH, ucode_vendors[i].filestr,
10146 10295 ucode_vendors[i].extstr);
10147 10296
10148 10297 if (stat(file, &fstatus) != 0 || !(S_ISREG(fstatus.st_mode)))
10149 10298 continue;
10150 10299
10151 10300 (void) snprintf(timestamp, PATH_MAX, "%s.ts", file);
10152 10301
10153 10302 if (stat(timestamp, &tstatus) == 0 &&
10154 10303 fstatus.st_mtime <= tstatus.st_mtime)
10155 10304 continue;
10156 10305
10157 10306 (void) snprintf(cmd, cmd_len, "/usr/sbin/ucodeadm -i -R "
10158 10307 "%s/%s/%s %s > /dev/null 2>&1", bam_root,
10159 10308 UCODE_INSTALL_PATH, ucode_vendors[i].vendorstr, file);
10160 10309 if (system(cmd) != 0)
10161 10310 return;
10162 10311
10163 10312 if (creat(timestamp, S_IRUSR | S_IWUSR) == -1)
10164 10313 return;
10165 10314
10166 10315 u_times.actime = fstatus.st_atime;
10167 10316 u_times.modtime = fstatus.st_mtime;
10168 10317 (void) utime(timestamp, &u_times);
10169 10318 }
10170 10319 }
10171 10320 #endif
↓ open down ↓ |
6004 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX