Home | History | Annotate | Download | only in extlinux
      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, &sects))
    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