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