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