1 /* ----------------------------------------------------------------------- * 2 * 3 * Copyright 1998-2008 H. Peter Anvin - All Rights Reserved 4 * Copyright 2009-2014 Intel Corporation; author: H. Peter Anvin 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, Inc., 53 Temple Place Ste 330, 9 * Boston MA 02111-1307, USA; either version 2 of the License, or 10 * (at your option) any later version; incorporated herein by reference. 11 * 12 * ----------------------------------------------------------------------- */ 13 14 /* 15 * extlinux.c 16 * 17 * Install the syslinux boot block on an fat, ntfs, ext2/3/4, btrfs, xfs, 18 * and ufs1/2 filesystem. 19 */ 20 21 #define _GNU_SOURCE /* Enable everything */ 22 #include <inttypes.h> 23 /* This is needed to deal with the kernel headers imported into glibc 3.3.3. */ 24 #include <alloca.h> 25 #include <errno.h> 26 #include <fcntl.h> 27 #include <stdio.h> 28 #include <unistd.h> 29 #include <dirent.h> 30 #ifndef __KLIBC__ 31 #include <mntent.h> 32 #endif 33 #include <stdbool.h> 34 #include <stddef.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <getopt.h> 38 #include <sysexits.h> 39 #include <sys/ioctl.h> 40 #include <sys/stat.h> 41 #include <sys/types.h> 42 #include <sys/mount.h> 43 #include <sys/vfs.h> 44 45 #include "linuxioctl.h" 46 47 #include "btrfs.h" 48 #include "fat.h" 49 #include "ntfs.h" 50 #include "xfs.h" 51 #include "xfs_types.h" 52 #include "xfs_sb.h" 53 #include "ufs.h" 54 #include "ufs_fs.h" 55 #include "misc.h" 56 #include "version.h" 57 #include "syslxint.h" 58 #include "syslxcom.h" /* common functions shared with extlinux and syslinux */ 59 #include "syslxfs.h" 60 #include "setadv.h" 61 #include "syslxopt.h" /* unified options */ 62 #include "mountinfo.h" 63 64 #ifdef DEBUG 65 # define dprintf printf 66 #else 67 # define dprintf(...) ((void)0) 68 #endif 69 70 #ifndef EXT2_SUPER_OFFSET 71 #define EXT2_SUPER_OFFSET 1024 72 #endif 73 74 /* Since we have unused 2048 bytes in the primary AG of an XFS partition, 75 * we will use the first 0~512 bytes starting from 2048 for the Syslinux 76 * boot sector. 77 */ 78 #define XFS_BOOTSECT_OFFSET (4 << SECTOR_SHIFT) 79 #define XFS_SUPPORTED_BLOCKSIZE 4096 /* 4 KiB filesystem block size */ 80 81 /* 82 * btrfs has two discontiguous areas reserved for the boot loader. 83 * Use the first one (Boot Area A) for the boot sector and the ADV, 84 * and the second one for "ldlinux.sys". 85 */ 86 #define BTRFS_EXTLINUX_OFFSET BTRFS_BOOT_AREA_B_OFFSET 87 #define BTRFS_EXTLINUX_SIZE BTRFS_BOOT_AREA_B_SIZE 88 #define BTRFS_SUBVOL_MAX 256 /* By btrfs specification */ 89 static char subvol[BTRFS_SUBVOL_MAX]; 90 91 #define BTRFS_ADV_OFFSET (BTRFS_BOOT_AREA_A_OFFSET + BTRFS_BOOT_AREA_A_SIZE \ 92 - 2*ADV_SIZE) 93 94 /* 95 * Get the size of a block device 96 */ 97 static uint64_t get_size(int devfd) 98 { 99 uint64_t bytes; 100 uint32_t sects; 101 struct stat st; 102 103 #ifdef BLKGETSIZE64 104 if (!ioctl(devfd, BLKGETSIZE64, &bytes)) 105 return bytes; 106 #endif 107 if (!ioctl(devfd, BLKGETSIZE, §s)) 108 return (uint64_t) sects << 9; 109 else if (!fstat(devfd, &st) && st.st_size) 110 return st.st_size; 111 else 112 return 0; 113 } 114 115 /* 116 * Get device geometry and partition offset 117 */ 118 struct geometry_table { 119 uint64_t bytes; 120 struct hd_geometry g; 121 }; 122 123 static int sysfs_get_offset(int devfd, unsigned long *start) 124 { 125 struct stat st; 126 char sysfs_name[128]; 127 FILE *f; 128 int rv; 129 130 if (fstat(devfd, &st)) 131 return -1; 132 133 if ((size_t)snprintf(sysfs_name, sizeof sysfs_name, 134 "/sys/dev/block/%u:%u/start", 135 major(st.st_rdev), minor(st.st_rdev)) 136 >= sizeof sysfs_name) 137 return -1; 138 139 f = fopen(sysfs_name, "r"); 140 if (!f) 141 return -1; 142 143 rv = fscanf(f, "%lu", start); 144 fclose(f); 145 146 return (rv == 1) ? 0 : -1; 147 } 148 149 /* Standard floppy disk geometries, plus LS-120. Zipdisk geometry 150 (x/64/32) is the final fallback. I don't know what LS-240 has 151 as its geometry, since I don't have one and don't know anyone that does, 152 and Google wasn't helpful... */ 153 static const struct geometry_table standard_geometries[] = { 154 {360 * 1024, {2, 9, 40, 0}}, 155 {720 * 1024, {2, 9, 80, 0}}, 156 {1200 * 1024, {2, 15, 80, 0}}, 157 {1440 * 1024, {2, 18, 80, 0}}, 158 {1680 * 1024, {2, 21, 80, 0}}, 159 {1722 * 1024, {2, 21, 80, 0}}, 160 {2880 * 1024, {2, 36, 80, 0}}, 161 {3840 * 1024, {2, 48, 80, 0}}, 162 {123264 * 1024, {8, 32, 963, 0}}, /* LS120 */ 163 {0, {0, 0, 0, 0}} 164 }; 165 166 int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo) 167 { 168 struct floppy_struct fd_str; 169 struct loop_info li; 170 struct loop_info64 li64; 171 const struct geometry_table *gp; 172 int rv = 0; 173 174 memset(geo, 0, sizeof *geo); 175 176 if (!ioctl(devfd, HDIO_GETGEO, geo)) { 177 goto ok; 178 } else if (!ioctl(devfd, FDGETPRM, &fd_str)) { 179 geo->heads = fd_str.head; 180 geo->sectors = fd_str.sect; 181 geo->cylinders = fd_str.track; 182 geo->start = 0; 183 goto ok; 184 } 185 186 /* Didn't work. Let's see if this is one of the standard geometries */ 187 for (gp = standard_geometries; gp->bytes; gp++) { 188 if (gp->bytes == totalbytes) { 189 memcpy(geo, &gp->g, sizeof *geo); 190 goto ok; 191 } 192 } 193 194 /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is 195 what zipdisks use, so this would help if someone has a USB key that 196 they're booting in USB-ZIP mode. */ 197 198 geo->heads = opt.heads ? : 64; 199 geo->sectors = opt.sectors ? : 32; 200 geo->cylinders = totalbytes / (geo->heads * geo->sectors << SECTOR_SHIFT); 201 geo->start = 0; 202 203 if (!opt.sectors && !opt.heads) { 204 fprintf(stderr, 205 "Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n" 206 " (on hard disks, this is usually harmless.)\n", 207 geo->heads, geo->sectors); 208 rv = 1; /* Suboptimal result */ 209 } 210 211 ok: 212 /* If this is a loopback device, try to set the start */ 213 if (!ioctl(devfd, LOOP_GET_STATUS64, &li64)) 214 geo->start = li64.lo_offset >> SECTOR_SHIFT; 215 else if (!ioctl(devfd, LOOP_GET_STATUS, &li)) 216 geo->start = (unsigned int)li.lo_offset >> SECTOR_SHIFT; 217 else if (!sysfs_get_offset(devfd, &geo->start)) { 218 /* OK */ 219 } 220 221 return rv; 222 } 223 224 /* 225 * Query the device geometry and put it into the boot sector. 226 * Map the file and put the map in the boot sector and file. 227 * Stick the "current directory" inode number into the file. 228 * 229 * Returns the number of modified bytes in the boot file. 230 */ 231 static int patch_file_and_bootblock(int fd, const char *dir, int devfd) 232 { 233 struct stat dirst, xdst; 234 struct hd_geometry geo; 235 sector_t *sectp; 236 uint64_t totalbytes, totalsectors; 237 int nsect; 238 struct fat_boot_sector *sbs; 239 char *dirpath, *subpath, *xdirpath; 240 int rv; 241 242 dirpath = realpath(dir, NULL); 243 if (!dirpath || stat(dir, &dirst)) { 244 perror("accessing install directory"); 245 exit(255); /* This should never happen */ 246 } 247 248 if (lstat(dirpath, &xdst) || 249 dirst.st_ino != xdst.st_ino || 250 dirst.st_dev != xdst.st_dev) { 251 perror("realpath returned nonsense"); 252 exit(255); 253 } 254 255 subpath = strchr(dirpath, '\0'); 256 for (;;) { 257 if (*subpath == '/') { 258 if (subpath > dirpath) { 259 *subpath = '\0'; 260 xdirpath = dirpath; 261 } else { 262 xdirpath = "/"; 263 } 264 if (lstat(xdirpath, &xdst) || dirst.st_dev != xdst.st_dev) { 265 subpath = strchr(subpath+1, '/'); 266 if (!subpath) 267 subpath = "/"; /* It's the root of the filesystem */ 268 break; 269 } 270 *subpath = '/'; 271 } 272 273 if (subpath == dirpath) 274 break; 275 276 subpath--; 277 } 278 279 /* Now subpath should contain the path relative to the fs base */ 280 dprintf("subpath = %s\n", subpath); 281 282 totalbytes = get_size(devfd); 283 get_geometry(devfd, totalbytes, &geo); 284 285 if (opt.heads) 286 geo.heads = opt.heads; 287 if (opt.sectors) 288 geo.sectors = opt.sectors; 289 290 /* Patch this into a fake FAT superblock. This isn't because 291 FAT is a good format in any way, it's because it lets the 292 early bootstrap share code with the FAT version. */ 293 dprintf("heads = %u, sect = %u\n", geo.heads, geo.sectors); 294 295 sbs = (struct fat_boot_sector *)syslinux_bootsect; 296 297 totalsectors = totalbytes >> SECTOR_SHIFT; 298 if (totalsectors >= 65536) { 299 set_16(&sbs->bsSectors, 0); 300 } else { 301 set_16(&sbs->bsSectors, totalsectors); 302 } 303 set_32(&sbs->bsHugeSectors, totalsectors); 304 305 set_16(&sbs->bsBytesPerSec, SECTOR_SIZE); 306 set_16(&sbs->bsSecPerTrack, geo.sectors); 307 set_16(&sbs->bsHeads, geo.heads); 308 set_32(&sbs->bsHiddenSecs, geo.start); 309 310 /* Construct the boot file map */ 311 312 dprintf("directory inode = %lu\n", (unsigned long)dirst.st_ino); 313 nsect = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT; 314 nsect += 2; /* Two sectors for the ADV */ 315 sectp = alloca(sizeof(sector_t) * nsect); 316 if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS || 317 fs_type == XFS || fs_type == UFS1 || fs_type == UFS2) { 318 if (sectmap(fd, sectp, nsect)) { 319 perror("bmap"); 320 exit(1); 321 } 322 } else if (fs_type == BTRFS) { 323 int i; 324 sector_t *sp = sectp; 325 326 for (i = 0; i < nsect - 2; i++) 327 *sp++ = BTRFS_EXTLINUX_OFFSET/SECTOR_SIZE + i; 328 for (i = 0; i < 2; i++) 329 *sp++ = BTRFS_ADV_OFFSET/SECTOR_SIZE + i; 330 } 331 332 /* Create the modified image in memory */ 333 rv = syslinux_patch(sectp, nsect, opt.stupid_mode, 334 opt.raid_mode, subpath, subvol); 335 336 free(dirpath); 337 return rv; 338 } 339 340 /* 341 * Install the boot block on the specified device. 342 * Must be run AFTER install_file()! 343 */ 344 int install_bootblock(int fd, const char *device) 345 { 346 struct ext2_super_block sb; 347 struct btrfs_super_block sb2; 348 struct fat_boot_sector sb3; 349 struct ntfs_boot_sector sb4; 350 xfs_sb_t sb5; 351 struct ufs_super_block sb6; 352 bool ok = false; 353 354 if (fs_type == EXT2) { 355 if (xpread(fd, &sb, sizeof sb, EXT2_SUPER_OFFSET) != sizeof sb) { 356 perror("reading superblock"); 357 return 1; 358 } 359 360 if (sb.s_magic == EXT2_SUPER_MAGIC) 361 ok = true; 362 } else if (fs_type == BTRFS) { 363 if (xpread(fd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET) 364 != sizeof sb2) { 365 perror("reading superblock"); 366 return 1; 367 } 368 if (!memcmp(sb2.magic, BTRFS_MAGIC, BTRFS_MAGIC_L)) 369 ok = true; 370 } else if (fs_type == VFAT) { 371 if (xpread(fd, &sb3, sizeof sb3, 0) != sizeof sb3) { 372 perror("reading fat superblock"); 373 return 1; 374 } 375 376 if (fat_check_sb_fields(&sb3)) 377 ok = true; 378 } else if (fs_type == NTFS) { 379 if (xpread(fd, &sb4, sizeof(sb4), 0) != sizeof(sb4)) { 380 perror("reading ntfs superblock"); 381 return 1; 382 } 383 384 if (ntfs_check_sb_fields(&sb4)) 385 ok = true; 386 } else if (fs_type == XFS) { 387 if (xpread(fd, &sb5, sizeof sb5, 0) != sizeof sb5) { 388 perror("reading xfs superblock"); 389 return 1; 390 } 391 392 if (sb5.sb_magicnum == *(u32 *)XFS_SB_MAGIC) { 393 if (be32_to_cpu(sb5.sb_blocksize) != XFS_SUPPORTED_BLOCKSIZE) { 394 fprintf(stderr, 395 "You need to have 4 KiB filesystem block size for " 396 " being able to install Syslinux in your XFS " 397 "partition (because there is no enough space in MBR to " 398 "determine where Syslinux bootsector can be installed " 399 "regardless the filesystem block size)\n"); 400 return 1; 401 } 402 403 ok = true; 404 } 405 } else if (fs_type == UFS1 || fs_type == UFS2) { 406 uint32_t sblock_off = (fs_type == UFS1) ? 407 SBLOCK_UFS1 : SBLOCK_UFS2; 408 uint32_t ufs_smagic = (fs_type == UFS1) ? 409 UFS1_SUPER_MAGIC : UFS2_SUPER_MAGIC; 410 411 if (xpread(fd, &sb6, sizeof sb6, sblock_off) != sizeof sb6) { 412 perror("reading superblock"); 413 return 1; 414 } 415 416 if (sb6.fs_magic == ufs_smagic) 417 ok = true; 418 } 419 420 if (!ok) { 421 fprintf(stderr, 422 "no fat, ntfs, ext2/3/4, btrfs, xfs " 423 "or ufs1/2 superblock found on %s\n", 424 device); 425 return 1; 426 } 427 428 if (fs_type == VFAT) { 429 struct fat_boot_sector *sbs = (struct fat_boot_sector *)syslinux_bootsect; 430 if (xpwrite(fd, &sbs->FAT_bsHead, FAT_bsHeadLen, 0) != FAT_bsHeadLen || 431 xpwrite(fd, &sbs->FAT_bsCode, FAT_bsCodeLen, 432 offsetof(struct fat_boot_sector, FAT_bsCode)) != FAT_bsCodeLen) { 433 perror("writing fat bootblock"); 434 return 1; 435 } 436 } else if (fs_type == NTFS) { 437 struct ntfs_boot_sector *sbs = 438 (struct ntfs_boot_sector *)syslinux_bootsect; 439 if (xpwrite(fd, &sbs->NTFS_bsHead, 440 NTFS_bsHeadLen, 0) != NTFS_bsHeadLen || 441 xpwrite(fd, &sbs->NTFS_bsCode, NTFS_bsCodeLen, 442 offsetof(struct ntfs_boot_sector, 443 NTFS_bsCode)) != NTFS_bsCodeLen) { 444 perror("writing ntfs bootblock"); 445 return 1; 446 } 447 } else if (fs_type == XFS) { 448 if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len, 449 XFS_BOOTSECT_OFFSET) != syslinux_bootsect_len) { 450 perror("writing xfs bootblock"); 451 return 1; 452 } 453 } else { 454 if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len, 0) 455 != syslinux_bootsect_len) { 456 perror("writing bootblock"); 457 return 1; 458 } 459 } 460 461 return 0; 462 } 463 464 static int rewrite_boot_image(int devfd, const char *path, const char *filename) 465 { 466 int fd; 467 int ret; 468 int modbytes; 469 470 /* Let's create LDLINUX.SYS file again (if it already exists, of course) */ 471 fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC, 472 S_IRUSR | S_IRGRP | S_IROTH); 473 if (fd < 0) { 474 perror(filename); 475 return -1; 476 } 477 478 /* Write boot image data into LDLINUX.SYS file */ 479 ret = xpwrite(fd, (const char _force *)boot_image, boot_image_len, 0); 480 if (ret != boot_image_len) { 481 perror("writing bootblock"); 482 goto error; 483 } 484 485 /* Write ADV */ 486 ret = xpwrite(fd, syslinux_adv, 2 * ADV_SIZE, boot_image_len); 487 if (ret != 2 * ADV_SIZE) { 488 fprintf(stderr, "%s: write failure on %s\n", program, filename); 489 goto error; 490 } 491 492 /* Map the file, and patch the initial sector accordingly */ 493 modbytes = patch_file_and_bootblock(fd, path, devfd); 494 495 /* Write the patch area again - this relies on the file being overwritten 496 * in place! */ 497 ret = xpwrite(fd, (const char _force *)boot_image, modbytes, 0); 498 if (ret != modbytes) { 499 fprintf(stderr, "%s: write failure on %s\n", program, filename); 500 goto error; 501 } 502 503 return fd; 504 505 error: 506 close(fd); 507 508 return -1; 509 } 510 511 int ext2_fat_install_file(const char *path, int devfd, struct stat *rst) 512 { 513 char *file, *oldfile, *c32file; 514 int fd = -1, dirfd = -1; 515 int r1, r2, r3; 516 517 r1 = asprintf(&file, "%s%sldlinux.sys", 518 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/"); 519 r2 = asprintf(&oldfile, "%s%sextlinux.sys", 520 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/"); 521 r3 = asprintf(&c32file, "%s%sldlinux.c32", 522 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/"); 523 if (r1 < 0 || !file || r2 < 0 || !oldfile || r3 < 0 || !c32file) { 524 perror(program); 525 return 1; 526 } 527 528 dirfd = open(path, O_RDONLY | O_DIRECTORY); 529 if (dirfd < 0) { 530 perror(path); 531 goto bail; 532 } 533 534 fd = open(file, O_RDONLY); 535 if (fd < 0) { 536 if (errno != ENOENT) { 537 perror(file); 538 goto bail; 539 } 540 } else { 541 clear_attributes(fd); 542 } 543 close(fd); 544 545 fd = rewrite_boot_image(devfd, path, file); 546 if (fd < 0) 547 goto bail; 548 549 /* Attempt to set immutable flag and remove all write access */ 550 /* Only set immutable flag if file is owned by root */ 551 set_attributes(fd); 552 553 if (fstat(fd, rst)) { 554 perror(file); 555 goto bail; 556 } 557 558 close(dirfd); 559 close(fd); 560 561 /* Look if we have the old filename */ 562 fd = open(oldfile, O_RDONLY); 563 if (fd >= 0) { 564 clear_attributes(fd); 565 close(fd); 566 unlink(oldfile); 567 } 568 569 fd = open(c32file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC, 570 S_IRUSR | S_IRGRP | S_IROTH); 571 if (fd < 0) { 572 perror(c32file); 573 goto bail; 574 } 575 576 r3 = xpwrite(fd, (const char _force *)syslinux_ldlinuxc32, 577 syslinux_ldlinuxc32_len, 0); 578 if (r3 != syslinux_ldlinuxc32_len) { 579 fprintf(stderr, "%s: write failure on %s\n", program, c32file); 580 goto bail; 581 } 582 583 free(file); 584 free(oldfile); 585 free(c32file); 586 return 0; 587 588 bail: 589 if (dirfd >= 0) 590 close(dirfd); 591 if (fd >= 0) 592 close(fd); 593 594 free(file); 595 free(oldfile); 596 free(c32file); 597 return 1; 598 } 599 600 /* btrfs has to install the ldlinux.sys in the first 64K blank area, which 601 is not managered by btrfs tree, so actually this is not installed as files. 602 since the cow feature of btrfs will move the ldlinux.sys every where */ 603 int btrfs_install_file(const char *path, int devfd, struct stat *rst) 604 { 605 char *file; 606 int fd, rv; 607 608 patch_file_and_bootblock(-1, path, devfd); 609 if (xpwrite(devfd, (const char _force *)boot_image, 610 boot_image_len, BTRFS_EXTLINUX_OFFSET) 611 != boot_image_len) { 612 perror("writing bootblock"); 613 return 1; 614 } 615 dprintf("write boot_image to 0x%x\n", BTRFS_EXTLINUX_OFFSET); 616 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET) 617 != 2 * ADV_SIZE) { 618 perror("writing adv"); 619 return 1; 620 } 621 dprintf("write adv to 0x%x\n", BTRFS_ADV_OFFSET); 622 if (stat(path, rst)) { 623 perror(path); 624 return 1; 625 } 626 627 /* 628 * Note that we *can* install ldinux.c32 as a regular file because 629 * it doesn't need to be within the first 64K. The Syslinux core 630 * has enough smarts to search the btrfs dirs and find this file. 631 */ 632 rv = asprintf(&file, "%s%sldlinux.c32", 633 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/"); 634 if (rv < 0 || !file) { 635 perror(program); 636 return 1; 637 } 638 639 fd = open(file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC, 640 S_IRUSR | S_IRGRP | S_IROTH); 641 if (fd < 0) { 642 perror(file); 643 free(file); 644 return 1; 645 } 646 647 rv = xpwrite(fd, (const char _force *)syslinux_ldlinuxc32, 648 syslinux_ldlinuxc32_len, 0); 649 if (rv != (int)syslinux_ldlinuxc32_len) { 650 fprintf(stderr, "%s: write failure on %s\n", program, file); 651 rv = 1; 652 } else 653 rv = 0; 654 655 close(fd); 656 free(file); 657 return rv; 658 } 659 660 /* 661 * Due to historical reasons (SGI IRIX's design of disk layouts), the first 662 * sector in the primary AG on XFS filesystems contains the superblock, which is 663 * a problem with bootloaders that rely on BIOSes (that load VBRs which are 664 * (located in the first sector of the partition). 665 * 666 * Thus, we need to handle this issue, otherwise Syslinux will damage the XFS's 667 * superblock. 668 */ 669 static int xfs_install_file(const char *path, int devfd, struct stat *rst) 670 { 671 static char file[PATH_MAX + 1]; 672 static char c32file[PATH_MAX + 1]; 673 int dirfd = -1; 674 int fd = -1; 675 int retval; 676 677 snprintf(file, PATH_MAX + 1, "%s%sldlinux.sys", path, 678 path[0] && path[strlen(path) - 1] == '/' ? "" : "/"); 679 snprintf(c32file, PATH_MAX + 1, "%s%sldlinux.c32", path, 680 path[0] && path[strlen(path) - 1] == '/' ? "" : "/"); 681 682 dirfd = open(path, O_RDONLY | O_DIRECTORY); 683 if (dirfd < 0) { 684 perror(path); 685 goto bail; 686 } 687 688 fd = open(file, O_RDONLY); 689 if (fd < 0) { 690 if (errno != ENOENT) { 691 perror(file); 692 goto bail; 693 } 694 } else { 695 clear_attributes(fd); 696 } 697 698 close(fd); 699 700 fd = rewrite_boot_image(devfd, path, file); 701 if (fd < 0) 702 goto bail; 703 704 /* Attempt to set immutable flag and remove all write access */ 705 /* Only set immutable flag if file is owned by root */ 706 set_attributes(fd); 707 708 if (fstat(fd, rst)) { 709 perror(file); 710 goto bail; 711 } 712 713 close(dirfd); 714 close(fd); 715 716 dirfd = -1; 717 fd = -1; 718 719 fd = open(c32file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC, 720 S_IRUSR | S_IRGRP | S_IROTH); 721 if (fd < 0) { 722 perror(c32file); 723 goto bail; 724 } 725 726 retval = xpwrite(fd, (const char _force *)syslinux_ldlinuxc32, 727 syslinux_ldlinuxc32_len, 0); 728 if (retval != (int)syslinux_ldlinuxc32_len) { 729 fprintf(stderr, "%s: write failure on %s\n", program, file); 730 goto bail; 731 } 732 733 close(fd); 734 735 sync(); 736 737 return 0; 738 739 bail: 740 if (dirfd >= 0) 741 close(dirfd); 742 743 if (fd >= 0) 744 close(fd); 745 746 return 1; 747 } 748 749 /* 750 * * test if path is a subvolume: 751 * * this function return 752 * * 0-> path exists but it is not a subvolume 753 * * 1-> path exists and it is a subvolume 754 * * -1 -> path is unaccessible 755 * */ 756 static int test_issubvolume(char *path) 757 { 758 759 struct stat st; 760 int res; 761 762 res = stat(path, &st); 763 if(res < 0 ) 764 return -1; 765 766 return (st.st_ino == 256) && S_ISDIR(st.st_mode); 767 768 } 769 770 /* 771 * Get the default subvolume of a btrfs filesystem 772 * rootdir: btrfs root dir 773 * subvol: this function will save the default subvolume name here 774 */ 775 static char * get_default_subvol(char * rootdir, char * subvol) 776 { 777 struct btrfs_ioctl_search_args args; 778 struct btrfs_ioctl_search_key *sk = &args.key; 779 struct btrfs_ioctl_search_header *sh; 780 int ret, i; 781 int fd; 782 struct btrfs_root_ref *ref; 783 struct btrfs_dir_item *dir_item; 784 unsigned long off = 0; 785 int name_len; 786 char *name; 787 char dirname[4096]; 788 u64 defaultsubvolid = 0; 789 790 ret = test_issubvolume(rootdir); 791 if (ret == 1) { 792 fd = open(rootdir, O_RDONLY); 793 if (fd < 0) { 794 fprintf(stderr, "ERROR: failed to open %s\n", rootdir); 795 } 796 ret = fd; 797 } 798 if (ret <= 0) { 799 subvol[0] = '\0'; 800 return NULL; 801 } 802 803 memset(&args, 0, sizeof(args)); 804 805 /* search in the tree of tree roots */ 806 sk->tree_id = 1; 807 808 /* 809 * set the min and max to backref keys. The search will 810 * only send back this type of key now. 811 */ 812 sk->max_type = BTRFS_DIR_ITEM_KEY; 813 sk->min_type = BTRFS_DIR_ITEM_KEY; 814 815 /* 816 * set all the other params to the max, we'll take any objectid 817 * and any trans 818 */ 819 sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID; 820 sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID; 821 822 sk->max_offset = (u64)-1; 823 sk->min_offset = 0; 824 sk->max_transid = (u64)-1; 825 826 /* just a big number, doesn't matter much */ 827 sk->nr_items = 4096; 828 829 while(1) { 830 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); 831 if (ret < 0) { 832 fprintf(stderr, "ERROR: can't perform the search\n"); 833 subvol[0] = '\0'; 834 return NULL; 835 } 836 /* the ioctl returns the number of item it found in nr_items */ 837 if (sk->nr_items == 0) { 838 break; 839 } 840 841 off = 0; 842 843 /* 844 * for each item, pull the key out of the header and then 845 * read the root_ref item it contains 846 */ 847 for (i = 0; i < sk->nr_items; i++) { 848 sh = (struct btrfs_ioctl_search_header *)(args.buf + off); 849 off += sizeof(*sh); 850 if (sh->type == BTRFS_DIR_ITEM_KEY) { 851 dir_item = (struct btrfs_dir_item *)(args.buf + off); 852 name_len = dir_item->name_len; 853 name = (char *)(dir_item + 1); 854 855 856 /*add_root(&root_lookup, sh->objectid, sh->offset, 857 dir_id, name, name_len);*/ 858 strncpy(dirname, name, name_len); 859 dirname[name_len] = '\0'; 860 if (strcmp(dirname, "default") == 0) { 861 defaultsubvolid = dir_item->location.objectid; 862 break; 863 } 864 } 865 off += sh->len; 866 867 /* 868 * record the mins in sk so we can make sure the 869 * next search doesn't repeat this root 870 */ 871 sk->min_objectid = sh->objectid; 872 sk->min_type = sh->type; 873 sk->max_type = sh->type; 874 sk->min_offset = sh->offset; 875 } 876 if (defaultsubvolid != 0) 877 break; 878 sk->nr_items = 4096; 879 /* this iteration is done, step forward one root for the next 880 * ioctl 881 */ 882 if (sk->min_objectid < (u64)-1) { 883 sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID; 884 sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID; 885 sk->max_type = BTRFS_ROOT_BACKREF_KEY; 886 sk->min_type = BTRFS_ROOT_BACKREF_KEY; 887 sk->min_offset = 0; 888 } else 889 break; 890 } 891 892 if (defaultsubvolid == 0) { 893 subvol[0] = '\0'; 894 return NULL; 895 } 896 897 memset(&args, 0, sizeof(args)); 898 899 /* search in the tree of tree roots */ 900 sk->tree_id = 1; 901 902 /* 903 * set the min and max to backref keys. The search will 904 * only send back this type of key now. 905 */ 906 sk->max_type = BTRFS_ROOT_BACKREF_KEY; 907 sk->min_type = BTRFS_ROOT_BACKREF_KEY; 908 909 /* 910 * set all the other params to the max, we'll take any objectid 911 * and any trans 912 */ 913 sk->max_objectid = (u64)-1; 914 sk->max_offset = (u64)-1; 915 sk->max_transid = (u64)-1; 916 917 /* just a big number, doesn't matter much */ 918 sk->nr_items = 4096; 919 920 while(1) { 921 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); 922 if (ret < 0) { 923 fprintf(stderr, "ERROR: can't perform the search\n"); 924 subvol[0] = '\0'; 925 return NULL; 926 } 927 /* the ioctl returns the number of item it found in nr_items */ 928 if (sk->nr_items == 0) 929 break; 930 931 off = 0; 932 933 /* 934 * for each item, pull the key out of the header and then 935 * read the root_ref item it contains 936 */ 937 for (i = 0; i < sk->nr_items; i++) { 938 sh = (struct btrfs_ioctl_search_header *)(args.buf + off); 939 off += sizeof(*sh); 940 if (sh->type == BTRFS_ROOT_BACKREF_KEY) { 941 ref = (struct btrfs_root_ref *)(args.buf + off); 942 name_len = ref->name_len; 943 name = (char *)(ref + 1); 944 945 if (sh->objectid == defaultsubvolid) { 946 strncpy(subvol, name, name_len); 947 subvol[name_len] = '\0'; 948 dprintf("The default subvolume: %s, ID: %llu\n", 949 subvol, sh->objectid); 950 break; 951 } 952 953 } 954 955 off += sh->len; 956 957 /* 958 * record the mins in sk so we can make sure the 959 * next search doesn't repeat this root 960 */ 961 sk->min_objectid = sh->objectid; 962 sk->min_type = sh->type; 963 sk->min_offset = sh->offset; 964 } 965 if (subvol[0] != '\0') 966 break; 967 sk->nr_items = 4096; 968 /* this iteration is done, step forward one root for the next 969 * ioctl 970 */ 971 if (sk->min_objectid < (u64)-1) { 972 sk->min_objectid++; 973 sk->min_type = BTRFS_ROOT_BACKREF_KEY; 974 sk->min_offset = 0; 975 } else 976 break; 977 } 978 return subvol; 979 } 980 981 static int install_file(const char *path, int devfd, struct stat *rst) 982 { 983 if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS 984 || fs_type == UFS1 || fs_type == UFS2) 985 return ext2_fat_install_file(path, devfd, rst); 986 else if (fs_type == BTRFS) 987 return btrfs_install_file(path, devfd, rst); 988 else if (fs_type == XFS) 989 return xfs_install_file(path, devfd, rst); 990 991 return 1; 992 } 993 994 #ifdef __KLIBC__ 995 static char devname_buf[64]; 996 997 static void device_cleanup(void) 998 { 999 unlink(devname_buf); 1000 } 1001 #endif 1002 1003 /* Verify that a device fd and a pathname agree. 1004 Return 0 on valid, -1 on error. */ 1005 static int validate_device_btrfs(int pathfd, int devfd); 1006 static int validate_device(const char *path, int devfd) 1007 { 1008 struct stat pst, dst; 1009 struct statfs sfs; 1010 int pfd; 1011 int rv = -1; 1012 1013 pfd = open(path, O_RDONLY|O_DIRECTORY); 1014 if (pfd < 0) 1015 goto err; 1016 1017 if (fstat(pfd, &pst) || fstat(devfd, &dst) || statfs(path, &sfs)) 1018 goto err; 1019 1020 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */ 1021 if (fs_type == BTRFS) { 1022 if (sfs.f_type == BTRFS_SUPER_MAGIC) 1023 rv = validate_device_btrfs(pfd, devfd); 1024 } else { 1025 rv = (pst.st_dev == dst.st_rdev) ? 0 : -1; 1026 } 1027 1028 err: 1029 if (pfd >= 0) 1030 close(pfd); 1031 return rv; 1032 } 1033 1034 #ifndef __KLIBC__ 1035 static const char *find_device(const char *mtab_file, dev_t dev) 1036 { 1037 struct mntent *mnt; 1038 struct stat dst; 1039 FILE *mtab; 1040 const char *devname = NULL; 1041 bool done; 1042 1043 mtab = setmntent(mtab_file, "r"); 1044 if (!mtab) 1045 return NULL; 1046 1047 done = false; 1048 while ((mnt = getmntent(mtab))) { 1049 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */ 1050 switch (fs_type) { 1051 case BTRFS: 1052 if (!strcmp(mnt->mnt_type, "btrfs") && 1053 !stat(mnt->mnt_dir, &dst) && 1054 dst.st_dev == dev) { 1055 if (!subvol[0]) 1056 get_default_subvol(mnt->mnt_dir, subvol); 1057 done = true; 1058 } 1059 break; 1060 case EXT2: 1061 if ((!strcmp(mnt->mnt_type, "ext2") || 1062 !strcmp(mnt->mnt_type, "ext3") || 1063 !strcmp(mnt->mnt_type, "ext4")) && 1064 !stat(mnt->mnt_fsname, &dst) && 1065 dst.st_rdev == dev) { 1066 done = true; 1067 break; 1068 } 1069 case VFAT: 1070 if ((!strcmp(mnt->mnt_type, "vfat")) && 1071 !stat(mnt->mnt_fsname, &dst) && 1072 dst.st_rdev == dev) { 1073 done = true; 1074 break; 1075 } 1076 case NTFS: 1077 if ((!strcmp(mnt->mnt_type, "fuseblk") /* ntfs-3g */ || 1078 !strcmp(mnt->mnt_type, "ntfs")) && 1079 !stat(mnt->mnt_fsname, &dst) && 1080 dst.st_rdev == dev) { 1081 done = true; 1082 break; 1083 } 1084 1085 break; 1086 case XFS: 1087 if (!strcmp(mnt->mnt_type, "xfs") && !stat(mnt->mnt_fsname, &dst) && 1088 dst.st_rdev == dev) { 1089 done = true; 1090 break; 1091 } 1092 1093 break; 1094 case UFS1: 1095 case UFS2: 1096 if (!strcmp(mnt->mnt_type, "ufs") && !stat(mnt->mnt_fsname, &dst) && 1097 dst.st_rdev == dev) { 1098 done = true; 1099 } 1100 1101 break; 1102 case NONE: 1103 break; 1104 } 1105 1106 if (done) { 1107 devname = strdup(mnt->mnt_fsname); 1108 break; 1109 } 1110 } 1111 1112 endmntent(mtab); 1113 1114 return devname; 1115 } 1116 #endif 1117 1118 /* 1119 * On newer Linux kernels we can use sysfs to get a backwards mapping 1120 * from device names to standard filenames 1121 */ 1122 static const char *find_device_sysfs(dev_t dev) 1123 { 1124 char sysname[64]; 1125 char linkname[PATH_MAX]; 1126 ssize_t llen; 1127 char *p, *q; 1128 char *buf = NULL; 1129 struct stat st; 1130 1131 snprintf(sysname, sizeof sysname, "/sys/dev/block/%u:%u", 1132 major(dev), minor(dev)); 1133 1134 llen = readlink(sysname, linkname, sizeof linkname); 1135 if (llen < 0 || llen >= sizeof linkname) 1136 goto err; 1137 1138 linkname[llen] = '\0'; 1139 1140 p = strrchr(linkname, '/'); 1141 p = p ? p+1 : linkname; /* Leave basename */ 1142 1143 buf = q = malloc(strlen(p) + 6); 1144 if (!buf) 1145 goto err; 1146 1147 memcpy(q, "/dev/", 5); 1148 q += 5; 1149 1150 while (*p) { 1151 *q++ = (*p == '!') ? '/' : *p; 1152 p++; 1153 } 1154 1155 *q = '\0'; 1156 1157 if (!stat(buf, &st) && st.st_dev == dev) 1158 return buf; /* Found it! */ 1159 1160 err: 1161 if (buf) 1162 free(buf); 1163 return NULL; 1164 } 1165 1166 static const char *find_device_mountinfo(const char *path, dev_t dev) 1167 { 1168 const struct mountinfo *m; 1169 struct stat st; 1170 1171 m = find_mount(path, NULL); 1172 if (!m) 1173 return NULL; 1174 1175 if (m->devpath[0] == '/' && m->dev == dev && 1176 !stat(m->devpath, &st) && S_ISBLK(st.st_mode) && st.st_rdev == dev) 1177 return m->devpath; 1178 else 1179 return NULL; 1180 } 1181 1182 static int validate_device_btrfs(int pfd, int dfd) 1183 { 1184 struct btrfs_ioctl_fs_info_args fsinfo; 1185 static struct btrfs_ioctl_dev_info_args devinfo; 1186 struct btrfs_super_block sb2; 1187 1188 if (ioctl(pfd, BTRFS_IOC_FS_INFO, &fsinfo)) 1189 return -1; 1190 1191 /* We do not support multi-device btrfs yet */ 1192 if (fsinfo.num_devices != 1) 1193 return -1; 1194 1195 /* The one device will have the max devid */ 1196 memset(&devinfo, 0, sizeof devinfo); 1197 devinfo.devid = fsinfo.max_id; 1198 if (ioctl(pfd, BTRFS_IOC_DEV_INFO, &devinfo)) 1199 return -1; 1200 1201 if (devinfo.path[0] != '/') 1202 return -1; 1203 1204 if (xpread(dfd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET) != sizeof sb2) 1205 return -1; 1206 1207 if (memcmp(sb2.magic, BTRFS_MAGIC, BTRFS_MAGIC_L)) 1208 return -1; 1209 1210 if (memcmp(sb2.fsid, fsinfo.fsid, sizeof fsinfo.fsid)) 1211 return -1; 1212 1213 if (sb2.num_devices != 1) 1214 return -1; 1215 1216 if (sb2.dev_item.devid != devinfo.devid) 1217 return -1; 1218 1219 if (memcmp(sb2.dev_item.uuid, devinfo.uuid, sizeof devinfo.uuid)) 1220 return -1; 1221 1222 if (memcmp(sb2.dev_item.fsid, fsinfo.fsid, sizeof fsinfo.fsid)) 1223 return -1; 1224 1225 return 0; /* It's good! */ 1226 } 1227 1228 static const char *find_device_btrfs(const char *path) 1229 { 1230 int pfd, dfd; 1231 struct btrfs_ioctl_fs_info_args fsinfo; 1232 static struct btrfs_ioctl_dev_info_args devinfo; 1233 const char *rv = NULL; 1234 1235 pfd = dfd = -1; 1236 1237 pfd = open(path, O_RDONLY); 1238 if (pfd < 0) 1239 goto err; 1240 1241 if (ioctl(pfd, BTRFS_IOC_FS_INFO, &fsinfo)) 1242 goto err; 1243 1244 /* We do not support multi-device btrfs yet */ 1245 if (fsinfo.num_devices != 1) 1246 goto err; 1247 1248 /* The one device will have the max devid */ 1249 memset(&devinfo, 0, sizeof devinfo); 1250 devinfo.devid = fsinfo.max_id; 1251 if (ioctl(pfd, BTRFS_IOC_DEV_INFO, &devinfo)) 1252 goto err; 1253 1254 if (devinfo.path[0] != '/') 1255 goto err; 1256 1257 dfd = open((const char *)devinfo.path, O_RDONLY); 1258 if (dfd < 0) 1259 goto err; 1260 1261 if (!validate_device_btrfs(pfd, dfd)) 1262 rv = (const char *)devinfo.path; /* It's good! */ 1263 1264 err: 1265 if (pfd >= 0) 1266 close(pfd); 1267 if (dfd >= 0) 1268 close(dfd); 1269 return rv; 1270 } 1271 1272 static const char *get_devname(const char *path) 1273 { 1274 const char *devname = NULL; 1275 struct stat st; 1276 struct statfs sfs; 1277 1278 if (stat(path, &st) || !S_ISDIR(st.st_mode)) { 1279 fprintf(stderr, "%s: Not a directory: %s\n", program, path); 1280 return devname; 1281 } 1282 if (statfs(path, &sfs)) { 1283 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno)); 1284 return devname; 1285 } 1286 1287 if (opt.device) 1288 devname = opt.device; 1289 1290 if (!devname){ 1291 if (fs_type == BTRFS) { 1292 /* For btrfs try to get the device name from btrfs itself */ 1293 devname = find_device_btrfs(path); 1294 } 1295 } 1296 1297 if (!devname) { 1298 devname = find_device_mountinfo(path, st.st_dev); 1299 } 1300 1301 #ifdef __KLIBC__ 1302 if (!devname) { 1303 devname = find_device_sysfs(st.st_dev); 1304 } 1305 if (!devname) { 1306 /* klibc doesn't have getmntent and friends; instead, just create 1307 a new device with the appropriate device type */ 1308 snprintf(devname_buf, sizeof devname_buf, "/tmp/dev-%u:%u", 1309 major(st.st_dev), minor(st.st_dev)); 1310 1311 if (mknod(devname_buf, S_IFBLK | 0600, st.st_dev)) { 1312 fprintf(stderr, "%s: cannot create device %s\n", program, devname); 1313 return devname; 1314 } 1315 1316 atexit(device_cleanup); /* unlink the device node on exit */ 1317 devname = devname_buf; 1318 } 1319 1320 #else 1321 if (!devname) { 1322 devname = find_device("/proc/mounts", st.st_dev); 1323 } 1324 if (!devname) { 1325 /* Didn't find it in /proc/mounts, try /etc/mtab */ 1326 devname = find_device("/etc/mtab", st.st_dev); 1327 } 1328 if (!devname) { 1329 devname = find_device_sysfs(st.st_dev); 1330 1331 fprintf(stderr, "%s: cannot find device for path %s\n", program, path); 1332 return devname; 1333 } 1334 1335 fprintf(stderr, "%s is device %s\n", path, devname); 1336 1337 #endif 1338 return devname; 1339 } 1340 1341 static int open_device(const char *path, struct stat *st, const char **_devname) 1342 { 1343 int devfd; 1344 const char *devname = NULL; 1345 struct statfs sfs; 1346 1347 if (st) 1348 if (stat(path, st) || !S_ISDIR(st->st_mode)) { 1349 fprintf(stderr, "%s: Not a directory: %s\n", program, path); 1350 return -1; 1351 } 1352 1353 if (statfs(path, &sfs)) { 1354 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno)); 1355 return -1; 1356 } 1357 1358 if (sfs.f_type == EXT2_SUPER_MAGIC) 1359 fs_type = EXT2; 1360 else if (sfs.f_type == BTRFS_SUPER_MAGIC) 1361 fs_type = BTRFS; 1362 else if (sfs.f_type == MSDOS_SUPER_MAGIC) 1363 fs_type = VFAT; 1364 else if (sfs.f_type == NTFS_SB_MAGIC || 1365 sfs.f_type == FUSE_SUPER_MAGIC /* ntfs-3g */) 1366 fs_type = NTFS; 1367 else if (sfs.f_type == XFS_SUPER_MAGIC) 1368 fs_type = XFS; 1369 else if (sfs.f_type == UFS1_SUPER_MAGIC) 1370 fs_type = UFS1; 1371 else if (sfs.f_type == UFS2_SUPER_MAGIC) 1372 fs_type = UFS2; 1373 1374 if (!fs_type) { 1375 fprintf(stderr, 1376 "%s: not a fat, ntfs, ext2/3/4, btrfs, xfs or" 1377 "ufs1/2 filesystem: %s\n", 1378 program, path); 1379 return -1; 1380 } 1381 1382 devfd = -1; 1383 devname = get_devname(path); 1384 if (_devname) 1385 *_devname = devname; 1386 1387 if ((devfd = open(devname, O_RDWR | O_SYNC)) < 0) { 1388 fprintf(stderr, "%s: cannot open device %s\n", program, devname); 1389 return -1; 1390 } 1391 1392 /* Verify that the device we opened is the device intended */ 1393 if (validate_device(path, devfd)) { 1394 fprintf(stderr, "%s: path %s doesn't match device %s\n", 1395 program, path, devname); 1396 close(devfd); 1397 return -1; 1398 } 1399 return devfd; 1400 } 1401 1402 static int btrfs_read_adv(int devfd) 1403 { 1404 if (xpread(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET) 1405 != 2 * ADV_SIZE) 1406 return -1; 1407 1408 return syslinux_validate_adv(syslinux_adv) ? 1 : 0; 1409 } 1410 1411 static inline int xfs_read_adv(int devfd) 1412 { 1413 const size_t adv_size = 2 * ADV_SIZE; 1414 1415 if (xpread(devfd, syslinux_adv, adv_size, boot_image_len) != adv_size) 1416 return -1; 1417 1418 return syslinux_validate_adv(syslinux_adv) ? 1 : 0; 1419 } 1420 1421 static int ext_read_adv(const char *path, int devfd, const char **namep) 1422 { 1423 int err; 1424 const char *name; 1425 1426 if (fs_type == BTRFS) { 1427 /* btrfs "ldlinux.sys" is in 64k blank area */ 1428 return btrfs_read_adv(devfd); 1429 } else if (fs_type == XFS) { 1430 /* XFS "ldlinux.sys" is in the first 2048 bytes of the primary AG */ 1431 return xfs_read_adv(devfd); 1432 } else { 1433 err = read_adv(path, name = "ldlinux.sys"); 1434 if (err == 2) /* ldlinux.sys does not exist */ 1435 err = read_adv(path, name = "extlinux.sys"); 1436 if (namep) 1437 *namep = name; 1438 return err; 1439 } 1440 } 1441 1442 static int ext_write_adv(const char *path, const char *cfg, int devfd) 1443 { 1444 if (fs_type == BTRFS) { /* btrfs "ldlinux.sys" is in 64k blank area */ 1445 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE, 1446 BTRFS_ADV_OFFSET) != 2 * ADV_SIZE) { 1447 perror("writing adv"); 1448 return 1; 1449 } 1450 return 0; 1451 } 1452 return write_adv(path, cfg); 1453 } 1454 1455 static int install_loader(const char *path, int update_only) 1456 { 1457 struct stat st, fst; 1458 int devfd, rv; 1459 const char *devname; 1460 1461 devfd = open_device(path, &st, &devname); 1462 if (devfd < 0) 1463 return 1; 1464 1465 if (update_only && !syslinux_already_installed(devfd)) { 1466 fprintf(stderr, "%s: no previous syslinux boot sector found\n", 1467 program); 1468 close(devfd); 1469 return 1; 1470 } 1471 1472 /* Read a pre-existing ADV, if already installed */ 1473 if (opt.reset_adv) { 1474 syslinux_reset_adv(syslinux_adv); 1475 } else if (ext_read_adv(path, devfd, NULL) < 0) { 1476 close(devfd); 1477 return 1; 1478 } 1479 1480 if (modify_adv() < 0) { 1481 close(devfd); 1482 return 1; 1483 } 1484 1485 /* Install ldlinux.sys */ 1486 if (install_file(path, devfd, &fst)) { 1487 close(devfd); 1488 return 1; 1489 } 1490 if (fst.st_dev != st.st_dev) { 1491 fprintf(stderr, "%s: file system changed under us - aborting!\n", 1492 program); 1493 close(devfd); 1494 return 1; 1495 } 1496 1497 sync(); 1498 rv = install_bootblock(devfd, devname); 1499 close(devfd); 1500 sync(); 1501 1502 return rv; 1503 } 1504 1505 /* 1506 * Modify the ADV of an existing installation 1507 */ 1508 int modify_existing_adv(const char *path) 1509 { 1510 const char *filename; 1511 int devfd; 1512 1513 devfd = open_device(path, NULL, NULL); 1514 if (devfd < 0) 1515 return 1; 1516 1517 if (ext_read_adv(path, devfd, &filename) < 0) { 1518 close(devfd); 1519 return 1; 1520 } 1521 if (modify_adv() < 0) { 1522 close(devfd); 1523 return 1; 1524 } 1525 if (ext_write_adv(path, filename, devfd) < 0) { 1526 close(devfd); 1527 return 1; 1528 } 1529 close(devfd); 1530 return 0; 1531 } 1532 1533 int main(int argc, char *argv[]) 1534 { 1535 parse_options(argc, argv, MODE_EXTLINUX); 1536 1537 if (!opt.directory || opt.install_mbr || opt.activate_partition) 1538 usage(EX_USAGE, 0); 1539 1540 if (opt.update_only == -1) { 1541 if (opt.reset_adv || opt.set_once || opt.menu_save) 1542 return modify_existing_adv(opt.directory); 1543 else 1544 usage(EX_USAGE, MODE_EXTLINUX); 1545 } 1546 1547 return install_loader(opt.directory, opt.update_only); 1548 } 1549