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