1 /* ----------------------------------------------------------------------- *
3 * Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
4 * Copyright 2009-2014 Intel Corporation; author: H. Peter Anvin
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.
12 * ----------------------------------------------------------------------- */
17 * Install the syslinux boot block on a fat, ntfs, ext2/3/4, btrfs, xfs,
18 * and ufs1/2 filesystem.
21 #define _GNU_SOURCE /* Enable everything */
23 /* This is needed to deal with the kernel headers imported into glibc 3.3.3. */
39 #include <sys/ioctl.h>
41 #include <sys/types.h>
42 #include <sys/mount.h>
45 #include "linuxioctl.h"
51 #include "xfs_types.h"
58 #include "syslxcom.h" /* common functions shared with extlinux and syslinux */
62 #include "syslxopt.h" /* unified options */
63 #include "mountinfo.h"
66 # define dprintf printf
68 # define dprintf(...) ((void)0)
71 #ifndef EXT2_SUPER_OFFSET
72 #define EXT2_SUPER_OFFSET 1024
75 /* Since we have unused 2048 bytes in the primary AG of an XFS partition,
76 * we will use the first 0~512 bytes starting from 2048 for the Syslinux
79 #define XFS_BOOTSECT_OFFSET (4 << SECTOR_SHIFT)
80 #define XFS_SUPPORTED_BLOCKSIZE 4096 /* 4 KiB filesystem block size */
83 * btrfs has two discontiguous areas reserved for the boot loader.
84 * Use the first one (Boot Area A) for the boot sector and the ADV,
85 * and the second one for "ldlinux.sys".
87 #define BTRFS_EXTLINUX_OFFSET BTRFS_BOOT_AREA_B_OFFSET
88 #define BTRFS_EXTLINUX_SIZE BTRFS_BOOT_AREA_B_SIZE
89 #define BTRFS_SUBVOL_MAX 256 /* By btrfs specification */
90 static char subvol
[BTRFS_SUBVOL_MAX
];
92 #define BTRFS_ADV_OFFSET (BTRFS_BOOT_AREA_A_OFFSET + BTRFS_BOOT_AREA_A_SIZE \
96 * Get the size of a block device
98 static uint64_t get_size(int devfd
)
105 if (!ioctl(devfd
, BLKGETSIZE64
, &bytes
))
108 if (!ioctl(devfd
, BLKGETSIZE
, §s
))
109 return (uint64_t) sects
<< 9;
110 else if (!fstat(devfd
, &st
) && st
.st_size
)
117 * Get device geometry and partition offset
119 struct geometry_table
{
121 struct hd_geometry g
;
124 static int sysfs_get_offset(int devfd
, unsigned long *start
)
127 char sysfs_name
[128];
131 if (fstat(devfd
, &st
))
134 if ((size_t)snprintf(sysfs_name
, sizeof sysfs_name
,
135 "/sys/dev/block/%u:%u/start",
136 major(st
.st_rdev
), minor(st
.st_rdev
))
137 >= sizeof sysfs_name
)
140 f
= fopen(sysfs_name
, "r");
144 rv
= fscanf(f
, "%lu", start
);
147 return (rv
== 1) ? 0 : -1;
150 /* Standard floppy disk geometries, plus LS-120. Zipdisk geometry
151 (x/64/32) is the final fallback. I don't know what LS-240 has
152 as its geometry, since I don't have one and don't know anyone that does,
153 and Google wasn't helpful... */
154 static const struct geometry_table standard_geometries
[] = {
155 {360 * 1024, {2, 9, 40, 0}},
156 {720 * 1024, {2, 9, 80, 0}},
157 {1200 * 1024, {2, 15, 80, 0}},
158 {1440 * 1024, {2, 18, 80, 0}},
159 {1680 * 1024, {2, 21, 80, 0}},
160 {1722 * 1024, {2, 21, 80, 0}},
161 {2880 * 1024, {2, 36, 80, 0}},
162 {3840 * 1024, {2, 48, 80, 0}},
163 {123264 * 1024, {8, 32, 963, 0}}, /* LS120 */
167 int get_geometry(int devfd
, uint64_t totalbytes
, struct hd_geometry
*geo
)
169 struct floppy_struct fd_str
;
171 struct loop_info64 li64
;
172 const struct geometry_table
*gp
;
175 memset(geo
, 0, sizeof *geo
);
177 if (!ioctl(devfd
, HDIO_GETGEO
, geo
)) {
179 } else if (!ioctl(devfd
, FDGETPRM
, &fd_str
)) {
180 geo
->heads
= fd_str
.head
;
181 geo
->sectors
= fd_str
.sect
;
182 geo
->cylinders
= fd_str
.track
;
187 /* Didn't work. Let's see if this is one of the standard geometries */
188 for (gp
= standard_geometries
; gp
->bytes
; gp
++) {
189 if (gp
->bytes
== totalbytes
) {
190 memcpy(geo
, &gp
->g
, sizeof *geo
);
195 /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is
196 what zipdisks use, so this would help if someone has a USB key that
197 they're booting in USB-ZIP mode. */
199 geo
->heads
= opt
.heads
? : 64;
200 geo
->sectors
= opt
.sectors
? : 32;
201 geo
->cylinders
= totalbytes
/ (geo
->heads
* geo
->sectors
<< SECTOR_SHIFT
);
204 if (!opt
.sectors
&& !opt
.heads
) {
206 "Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n"
207 " (on hard disks, this is usually harmless.)\n",
208 geo
->heads
, geo
->sectors
);
209 rv
= 1; /* Suboptimal result */
213 /* If this is a loopback device, try to set the start */
214 if (!ioctl(devfd
, LOOP_GET_STATUS64
, &li64
))
215 geo
->start
= li64
.lo_offset
>> SECTOR_SHIFT
;
216 else if (!ioctl(devfd
, LOOP_GET_STATUS
, &li
))
217 geo
->start
= (unsigned int)li
.lo_offset
>> SECTOR_SHIFT
;
218 else if (!sysfs_get_offset(devfd
, &geo
->start
)) {
226 * Query the device geometry and put it into the boot sector.
227 * Map the file and put the map in the boot sector and file.
228 * Stick the "current directory" inode number into the file.
230 * Returns the number of modified bytes in the boot file.
232 static int patch_file_and_bootblock(int fd
, const char *dir
, int devfd
)
234 struct stat dirst
, xdst
;
235 struct hd_geometry geo
;
237 uint64_t totalbytes
, totalsectors
;
239 struct fat_boot_sector
*sbs
;
240 char *dirpath
, *subpath
, *xdirpath
;
243 dirpath
= realpath(dir
, NULL
);
244 if (!dirpath
|| stat(dir
, &dirst
)) {
245 perror("accessing install directory");
246 exit(255); /* This should never happen */
249 if (lstat(dirpath
, &xdst
) ||
250 dirst
.st_ino
!= xdst
.st_ino
||
251 dirst
.st_dev
!= xdst
.st_dev
) {
252 perror("realpath returned nonsense");
256 subpath
= strchr(dirpath
, '\0');
258 if (*subpath
== '/') {
259 if (subpath
> dirpath
) {
265 if (lstat(xdirpath
, &xdst
) || dirst
.st_dev
!= xdst
.st_dev
) {
266 subpath
= strchr(subpath
+1, '/');
268 subpath
= "/"; /* It's the root of the filesystem */
274 if (subpath
== dirpath
)
280 /* Now subpath should contain the path relative to the fs base */
281 dprintf("subpath = %s\n", subpath
);
283 totalbytes
= get_size(devfd
);
284 get_geometry(devfd
, totalbytes
, &geo
);
287 geo
.heads
= opt
.heads
;
289 geo
.sectors
= opt
.sectors
;
291 /* Patch this into a fake FAT superblock. This isn't because
292 FAT is a good format in any way, it's because it lets the
293 early bootstrap share code with the FAT version. */
294 dprintf("heads = %u, sect = %u\n", geo
.heads
, geo
.sectors
);
296 sbs
= (struct fat_boot_sector
*)syslinux_bootsect
;
298 totalsectors
= totalbytes
>> SECTOR_SHIFT
;
299 if (totalsectors
>= 65536) {
300 set_16(&sbs
->bsSectors
, 0);
302 set_16(&sbs
->bsSectors
, totalsectors
);
304 set_32(&sbs
->bsHugeSectors
, totalsectors
);
306 set_16(&sbs
->bsBytesPerSec
, SECTOR_SIZE
);
307 set_16(&sbs
->bsSecPerTrack
, geo
.sectors
);
308 set_16(&sbs
->bsHeads
, geo
.heads
);
309 set_32(&sbs
->bsHiddenSecs
, geo
.start
);
311 /* Construct the boot file map */
313 dprintf("directory inode = %lu\n", (unsigned long)dirst
.st_ino
);
314 nsect
= (boot_image_len
+ SECTOR_SIZE
- 1) >> SECTOR_SHIFT
;
315 nsect
+= 2; /* Two sectors for the ADV */
316 sectp
= alloca(sizeof(sector_t
) * nsect
);
317 if (fs_type
== EXT2
|| fs_type
== VFAT
|| fs_type
== NTFS
||
318 fs_type
== XFS
|| fs_type
== UFS1
|| fs_type
== UFS2
) {
319 if (sectmap(fd
, sectp
, nsect
)) {
323 } else if (fs_type
== BTRFS
) {
325 sector_t
*sp
= sectp
;
327 for (i
= 0; i
< nsect
- 2; i
++)
328 *sp
++ = BTRFS_EXTLINUX_OFFSET
/SECTOR_SIZE
+ i
;
329 for (i
= 0; i
< 2; i
++)
330 *sp
++ = BTRFS_ADV_OFFSET
/SECTOR_SIZE
+ i
;
333 /* Create the modified image in memory */
334 rv
= syslinux_patch(sectp
, nsect
, opt
.stupid_mode
,
335 opt
.raid_mode
, subpath
, subvol
);
342 * Install the boot block on the specified device.
343 * Must be run AFTER install_file()!
345 int install_bootblock(int fd
, const char *device
)
347 struct ext2_super_block sb
;
348 struct btrfs_super_block sb2
;
349 struct fat_boot_sector sb3
;
350 struct ntfs_boot_sector sb4
;
352 struct ufs_super_block sb6
;
355 if (fs_type
== EXT2
) {
356 if (xpread(fd
, &sb
, sizeof sb
, EXT2_SUPER_OFFSET
) != sizeof sb
) {
357 perror("reading superblock");
361 if (sb
.s_magic
== EXT2_SUPER_MAGIC
)
363 } else if (fs_type
== BTRFS
) {
364 if (xpread(fd
, &sb2
, sizeof sb2
, BTRFS_SUPER_INFO_OFFSET
)
366 perror("reading superblock");
369 if (!memcmp(sb2
.magic
, BTRFS_MAGIC
, BTRFS_MAGIC_L
))
371 } else if (fs_type
== VFAT
) {
372 if (xpread(fd
, &sb3
, sizeof sb3
, 0) != sizeof sb3
) {
373 perror("reading fat superblock");
377 if (fat_check_sb_fields(&sb3
))
379 } else if (fs_type
== NTFS
) {
380 if (xpread(fd
, &sb4
, sizeof(sb4
), 0) != sizeof(sb4
)) {
381 perror("reading ntfs superblock");
385 if (ntfs_check_sb_fields(&sb4
))
387 } else if (fs_type
== XFS
) {
388 if (xpread(fd
, &sb5
, sizeof sb5
, 0) != sizeof sb5
) {
389 perror("reading xfs superblock");
393 if (sb5
.sb_magicnum
== *(u32
*)XFS_SB_MAGIC
) {
394 if (be32_to_cpu(sb5
.sb_blocksize
) != XFS_SUPPORTED_BLOCKSIZE
) {
396 "You need to have 4 KiB filesystem block size for "
397 " being able to install Syslinux in your XFS "
398 "partition (because there is no enough space in MBR to "
399 "determine where Syslinux bootsector can be installed "
400 "regardless the filesystem block size)\n");
406 } else if (fs_type
== UFS1
|| fs_type
== UFS2
) {
407 uint32_t sblock_off
= (fs_type
== UFS1
) ?
408 SBLOCK_UFS1
: SBLOCK_UFS2
;
409 uint32_t ufs_smagic
= (fs_type
== UFS1
) ?
410 UFS1_SUPER_MAGIC
: UFS2_SUPER_MAGIC
;
412 if (xpread(fd
, &sb6
, sizeof sb6
, sblock_off
) != sizeof sb6
) {
413 perror("reading superblock");
417 if (sb6
.fs_magic
== ufs_smagic
)
423 "no fat, ntfs, ext2/3/4, btrfs, xfs "
424 "or ufs1/2 superblock found on %s\n",
429 if (fs_type
== VFAT
) {
430 struct fat_boot_sector
*sbs
= (struct fat_boot_sector
*)syslinux_bootsect
;
431 if (xpwrite(fd
, &sbs
->FAT_bsHead
, FAT_bsHeadLen
, 0) != FAT_bsHeadLen
||
432 xpwrite(fd
, &sbs
->FAT_bsCode
, FAT_bsCodeLen
,
433 offsetof(struct fat_boot_sector
, FAT_bsCode
)) != FAT_bsCodeLen
) {
434 perror("writing fat bootblock");
437 } else if (fs_type
== NTFS
) {
438 struct ntfs_boot_sector
*sbs
=
439 (struct ntfs_boot_sector
*)syslinux_bootsect
;
440 if (xpwrite(fd
, &sbs
->NTFS_bsHead
,
441 NTFS_bsHeadLen
, 0) != NTFS_bsHeadLen
||
442 xpwrite(fd
, &sbs
->NTFS_bsCode
, NTFS_bsCodeLen
,
443 offsetof(struct ntfs_boot_sector
,
444 NTFS_bsCode
)) != NTFS_bsCodeLen
) {
445 perror("writing ntfs bootblock");
448 } else if (fs_type
== XFS
) {
449 if (xpwrite(fd
, syslinux_bootsect
, syslinux_bootsect_len
,
450 XFS_BOOTSECT_OFFSET
) != syslinux_bootsect_len
) {
451 perror("writing xfs bootblock");
455 if (xpwrite(fd
, syslinux_bootsect
, syslinux_bootsect_len
, 0)
456 != syslinux_bootsect_len
) {
457 perror("writing bootblock");
465 static int rewrite_boot_image(int devfd
, const char *path
, const char *filename
)
471 /* Let's create LDLINUX.SYS file again (if it already exists, of course) */
472 fd
= open(filename
, O_WRONLY
| O_TRUNC
| O_CREAT
| O_SYNC
,
473 S_IRUSR
| S_IRGRP
| S_IROTH
);
479 /* Write boot image data into LDLINUX.SYS file */
480 ret
= xpwrite(fd
, (const char _force
*)boot_image
, boot_image_len
, 0);
481 if (ret
!= boot_image_len
) {
482 perror("writing bootblock");
487 ret
= xpwrite(fd
, syslinux_adv
, 2 * ADV_SIZE
, boot_image_len
);
488 if (ret
!= 2 * ADV_SIZE
) {
489 fprintf(stderr
, "%s: write failure on %s\n", program
, filename
);
493 /* Map the file, and patch the initial sector accordingly */
494 modbytes
= patch_file_and_bootblock(fd
, path
, devfd
);
496 /* Write the patch area again - this relies on the file being overwritten
498 ret
= xpwrite(fd
, (const char _force
*)boot_image
, modbytes
, 0);
499 if (ret
!= modbytes
) {
500 fprintf(stderr
, "%s: write failure on %s\n", program
, filename
);
512 int ext2_fat_install_file(const char *path
, int devfd
, struct stat
*rst
)
514 char *file
, *oldfile
, *c32file
;
515 int fd
= -1, dirfd
= -1;
518 r1
= asprintf(&file
, "%s%sldlinux.sys",
519 path
, path
[0] && path
[strlen(path
) - 1] == '/' ? "" : "/");
520 r2
= asprintf(&oldfile
, "%s%sextlinux.sys",
521 path
, path
[0] && path
[strlen(path
) - 1] == '/' ? "" : "/");
522 r3
= asprintf(&c32file
, "%s%sldlinux.c32",
523 path
, path
[0] && path
[strlen(path
) - 1] == '/' ? "" : "/");
524 if (r1
< 0 || !file
|| r2
< 0 || !oldfile
|| r3
< 0 || !c32file
) {
529 dirfd
= open(path
, O_RDONLY
| O_DIRECTORY
);
535 fd
= open(file
, O_RDONLY
);
537 if (errno
!= ENOENT
) {
542 clear_attributes(fd
);
546 fd
= rewrite_boot_image(devfd
, path
, file
);
550 /* Attempt to set immutable flag and remove all write access */
551 /* Only set immutable flag if file is owned by root */
554 if (fstat(fd
, rst
)) {
562 /* Look if we have the old filename */
563 fd
= open(oldfile
, O_RDONLY
);
565 clear_attributes(fd
);
570 fd
= open(c32file
, O_WRONLY
| O_TRUNC
| O_CREAT
| O_SYNC
,
571 S_IRUSR
| S_IRGRP
| S_IROTH
);
577 r3
= xpwrite(fd
, (const char _force
*)syslinux_ldlinuxc32
,
578 syslinux_ldlinuxc32_len
, 0);
579 if (r3
!= syslinux_ldlinuxc32_len
) {
580 fprintf(stderr
, "%s: write failure on %s\n", program
, c32file
);
601 /* btrfs has to install ldlinux.sys to a boot area, which is not managed by
602 btrfs tree, so actually this is not installed as a file, since the cow
603 feature of btrfs would move the ldlinux.sys file everywhere. Older
604 versions installed it to the first 64kiB (aka Boot Area A) but as of
605 commit ID 37eef640 (before 6.03-pre12, before 6.03), it is now in Boot
606 Area B (a 768kiB blank space at offset 256kiB). */
607 int btrfs_install_file(const char *path
, int devfd
, struct stat
*rst
)
612 patch_file_and_bootblock(-1, path
, devfd
);
613 if (xpwrite(devfd
, (const char _force
*)boot_image
,
614 boot_image_len
, BTRFS_EXTLINUX_OFFSET
)
616 perror("writing bootblock");
619 dprintf("write boot_image to 0x%x\n", BTRFS_EXTLINUX_OFFSET
);
620 if (xpwrite(devfd
, syslinux_adv
, 2 * ADV_SIZE
, BTRFS_ADV_OFFSET
)
622 perror("writing adv");
625 dprintf("write adv to 0x%x\n", BTRFS_ADV_OFFSET
);
626 if (stat(path
, rst
)) {
632 * Note that we *can* install ldinux.c32 as a regular file because
633 * it doesn't need to be within the first 64K. The Syslinux core
634 * has enough smarts to search the btrfs dirs and find this file.
636 rv
= asprintf(&file
, "%s%sldlinux.c32",
637 path
, path
[0] && path
[strlen(path
) - 1] == '/' ? "" : "/");
638 if (rv
< 0 || !file
) {
643 fd
= open(file
, O_WRONLY
| O_TRUNC
| O_CREAT
| O_SYNC
,
644 S_IRUSR
| S_IRGRP
| S_IROTH
);
651 rv
= xpwrite(fd
, (const char _force
*)syslinux_ldlinuxc32
,
652 syslinux_ldlinuxc32_len
, 0);
653 if (rv
!= (int)syslinux_ldlinuxc32_len
) {
654 fprintf(stderr
, "%s: write failure on %s\n", program
, file
);
665 * Due to historical reasons (SGI IRIX's design of disk layouts), the first
666 * sector in the primary AG on XFS filesystems contains the superblock, which is
667 * a problem with bootloaders that rely on BIOSes (that load VBRs which are
668 * located in the first sector of the partition).
670 * Thus, we need to handle this issue, otherwise Syslinux will damage the XFS's
673 static int xfs_install_file(const char *path
, int devfd
, struct stat
*rst
)
675 static char file
[PATH_MAX
+ 1];
676 static char c32file
[PATH_MAX
+ 1];
681 snprintf(file
, PATH_MAX
+ 1, "%s%sldlinux.sys", path
,
682 path
[0] && path
[strlen(path
) - 1] == '/' ? "" : "/");
683 snprintf(c32file
, PATH_MAX
+ 1, "%s%sldlinux.c32", path
,
684 path
[0] && path
[strlen(path
) - 1] == '/' ? "" : "/");
686 dirfd
= open(path
, O_RDONLY
| O_DIRECTORY
);
692 fd
= open(file
, O_RDONLY
);
694 if (errno
!= ENOENT
) {
699 clear_attributes(fd
);
704 fd
= rewrite_boot_image(devfd
, path
, file
);
708 /* Attempt to set immutable flag and remove all write access */
709 /* Only set immutable flag if file is owned by root */
712 if (fstat(fd
, rst
)) {
723 fd
= open(c32file
, O_WRONLY
| O_TRUNC
| O_CREAT
| O_SYNC
,
724 S_IRUSR
| S_IRGRP
| S_IROTH
);
730 retval
= xpwrite(fd
, (const char _force
*)syslinux_ldlinuxc32
,
731 syslinux_ldlinuxc32_len
, 0);
732 if (retval
!= (int)syslinux_ldlinuxc32_len
) {
733 fprintf(stderr
, "%s: write failure on %s\n", program
, file
);
754 * * test if path is a subvolume:
755 * * this function return
756 * * 0-> path exists but it is not a subvolume
757 * * 1-> path exists and it is a subvolume
758 * * -1 -> path is unaccessible
760 static int test_issubvolume(char *path
)
766 res
= stat(path
, &st
);
770 return (st
.st_ino
== 256) && S_ISDIR(st
.st_mode
);
775 * Get the default subvolume of a btrfs filesystem
776 * rootdir: btrfs root dir
777 * subvol: this function will save the default subvolume name here
779 static char * get_default_subvol(char * rootdir
, char * subvol
)
781 struct btrfs_ioctl_search_args args
;
782 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
783 struct btrfs_ioctl_search_header
*sh
;
786 struct btrfs_root_ref
*ref
;
787 struct btrfs_dir_item
*dir_item
;
788 unsigned long off
= 0;
792 u64 defaultsubvolid
= 0;
794 ret
= test_issubvolume(rootdir
);
796 fd
= open(rootdir
, O_RDONLY
);
798 fprintf(stderr
, "ERROR: failed to open %s\n", rootdir
);
807 memset(&args
, 0, sizeof(args
));
809 /* search in the tree of tree roots */
813 * set the min and max to backref keys. The search will
814 * only send back this type of key now.
816 sk
->max_type
= BTRFS_DIR_ITEM_KEY
;
817 sk
->min_type
= BTRFS_DIR_ITEM_KEY
;
820 * set all the other params to the max, we'll take any objectid
823 sk
->min_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
824 sk
->max_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
826 sk
->max_offset
= (u64
)-1;
828 sk
->max_transid
= (u64
)-1;
830 /* just a big number, doesn't matter much */
834 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
836 fprintf(stderr
, "ERROR: can't perform the search\n");
840 /* the ioctl returns the number of item it found in nr_items */
841 if (sk
->nr_items
== 0) {
848 * for each item, pull the key out of the header and then
849 * read the root_ref item it contains
851 for (i
= 0; i
< sk
->nr_items
; i
++) {
852 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+ off
);
854 if (sh
->type
== BTRFS_DIR_ITEM_KEY
) {
855 dir_item
= (struct btrfs_dir_item
*)(args
.buf
+ off
);
856 name_len
= dir_item
->name_len
;
857 name
= (char *)(dir_item
+ 1);
860 /*add_root(&root_lookup, sh->objectid, sh->offset,
861 dir_id, name, name_len);*/
862 strncpy(dirname
, name
, name_len
);
863 dirname
[name_len
] = '\0';
864 if (strcmp(dirname
, "default") == 0) {
865 defaultsubvolid
= dir_item
->location
.objectid
;
872 * record the mins in sk so we can make sure the
873 * next search doesn't repeat this root
875 sk
->min_objectid
= sh
->objectid
;
876 sk
->min_type
= sh
->type
;
877 sk
->max_type
= sh
->type
;
878 sk
->min_offset
= sh
->offset
;
880 if (defaultsubvolid
!= 0)
883 /* this iteration is done, step forward one root for the next
886 if (sk
->min_objectid
< (u64
)-1) {
887 sk
->min_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
888 sk
->max_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
889 sk
->max_type
= BTRFS_ROOT_BACKREF_KEY
;
890 sk
->min_type
= BTRFS_ROOT_BACKREF_KEY
;
896 if (defaultsubvolid
== 0) {
901 memset(&args
, 0, sizeof(args
));
903 /* search in the tree of tree roots */
907 * set the min and max to backref keys. The search will
908 * only send back this type of key now.
910 sk
->max_type
= BTRFS_ROOT_BACKREF_KEY
;
911 sk
->min_type
= BTRFS_ROOT_BACKREF_KEY
;
914 * set all the other params to the max, we'll take any objectid
917 sk
->max_objectid
= (u64
)-1;
918 sk
->max_offset
= (u64
)-1;
919 sk
->max_transid
= (u64
)-1;
921 /* just a big number, doesn't matter much */
925 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
927 fprintf(stderr
, "ERROR: can't perform the search\n");
931 /* the ioctl returns the number of item it found in nr_items */
932 if (sk
->nr_items
== 0)
938 * for each item, pull the key out of the header and then
939 * read the root_ref item it contains
941 for (i
= 0; i
< sk
->nr_items
; i
++) {
942 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+ off
);
944 if (sh
->type
== BTRFS_ROOT_BACKREF_KEY
) {
945 ref
= (struct btrfs_root_ref
*)(args
.buf
+ off
);
946 name_len
= ref
->name_len
;
947 name
= (char *)(ref
+ 1);
949 if (sh
->objectid
== defaultsubvolid
) {
950 strncpy(subvol
, name
, name_len
);
951 subvol
[name_len
] = '\0';
952 dprintf("The default subvolume: %s, ID: %llu\n",
953 subvol
, sh
->objectid
);
962 * record the mins in sk so we can make sure the
963 * next search doesn't repeat this root
965 sk
->min_objectid
= sh
->objectid
;
966 sk
->min_type
= sh
->type
;
967 sk
->min_offset
= sh
->offset
;
969 if (subvol
[0] != '\0')
972 /* this iteration is done, step forward one root for the next
975 if (sk
->min_objectid
< (u64
)-1) {
977 sk
->min_type
= BTRFS_ROOT_BACKREF_KEY
;
985 static int install_file(const char *path
, int devfd
, struct stat
*rst
)
987 if (fs_type
== EXT2
|| fs_type
== VFAT
|| fs_type
== NTFS
988 || fs_type
== UFS1
|| fs_type
== UFS2
)
989 return ext2_fat_install_file(path
, devfd
, rst
);
990 else if (fs_type
== BTRFS
)
991 return btrfs_install_file(path
, devfd
, rst
);
992 else if (fs_type
== XFS
)
993 return xfs_install_file(path
, devfd
, rst
);
999 static char devname_buf
[64];
1001 static void device_cleanup(void)
1003 unlink(devname_buf
);
1007 /* Verify that a device fd and a pathname agree.
1008 Return 0 on valid, -1 on error. */
1009 static int validate_device_btrfs(int pathfd
, int devfd
);
1010 static int validate_device(const char *path
, int devfd
)
1012 struct stat pst
, dst
;
1017 pfd
= open(path
, O_RDONLY
|O_DIRECTORY
);
1021 if (fstat(pfd
, &pst
) || fstat(devfd
, &dst
) || statfs(path
, &sfs
))
1024 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
1025 if (fs_type
== BTRFS
) {
1026 if (sfs
.f_type
== BTRFS_SUPER_MAGIC
)
1027 rv
= validate_device_btrfs(pfd
, devfd
);
1029 rv
= (pst
.st_dev
== dst
.st_rdev
) ? 0 : -1;
1039 static char *find_device(const char *mtab_file
, dev_t dev
)
1044 char *devname
= NULL
;
1047 mtab
= setmntent(mtab_file
, "r");
1052 while ((mnt
= getmntent(mtab
))) {
1053 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
1056 if (!strcmp(mnt
->mnt_type
, "btrfs") &&
1057 !stat(mnt
->mnt_dir
, &dst
) &&
1058 dst
.st_dev
== dev
) {
1060 get_default_subvol(mnt
->mnt_dir
, subvol
);
1065 if ((!strcmp(mnt
->mnt_type
, "ext2") ||
1066 !strcmp(mnt
->mnt_type
, "ext3") ||
1067 !strcmp(mnt
->mnt_type
, "ext4")) &&
1068 !stat(mnt
->mnt_fsname
, &dst
) &&
1069 dst
.st_rdev
== dev
) {
1074 if ((!strcmp(mnt
->mnt_type
, "vfat")) &&
1075 !stat(mnt
->mnt_fsname
, &dst
) &&
1076 dst
.st_rdev
== dev
) {
1081 if ((!strcmp(mnt
->mnt_type
, "fuseblk") /* ntfs-3g */ ||
1082 !strcmp(mnt
->mnt_type
, "ntfs")) &&
1083 !stat(mnt
->mnt_fsname
, &dst
) &&
1084 dst
.st_rdev
== dev
) {
1091 if (!strcmp(mnt
->mnt_type
, "xfs") && !stat(mnt
->mnt_fsname
, &dst
) &&
1092 dst
.st_rdev
== dev
) {
1100 if (!strcmp(mnt
->mnt_type
, "ufs") && !stat(mnt
->mnt_fsname
, &dst
) &&
1101 dst
.st_rdev
== dev
) {
1111 devname
= strdup(mnt
->mnt_fsname
);
1123 * On newer Linux kernels we can use sysfs to get a backwards mapping
1124 * from device names to standard filenames
1126 static char *find_device_sysfs(dev_t dev
)
1129 char linkname
[PATH_MAX
];
1135 snprintf(sysname
, sizeof sysname
, "/sys/dev/block/%u:%u",
1136 major(dev
), minor(dev
));
1138 llen
= readlink(sysname
, linkname
, sizeof linkname
);
1139 if (llen
< 0 || llen
>= sizeof linkname
)
1142 linkname
[llen
] = '\0';
1144 p
= strrchr(linkname
, '/');
1145 p
= p
? p
+1 : linkname
; /* Leave basename */
1147 buf
= q
= malloc(strlen(p
) + 6);
1151 memcpy(q
, "/dev/", 5);
1155 *q
++ = (*p
== '!') ? '/' : *p
;
1161 if (!stat(buf
, &st
) && st
.st_dev
== dev
)
1162 return buf
; /* Found it! */
1170 static const char *find_device_mountinfo(const char *path
, dev_t dev
)
1172 const struct mountinfo
*m
;
1175 m
= find_mount(path
, NULL
);
1179 if (m
->devpath
[0] == '/' && m
->dev
== dev
&&
1180 !stat(m
->devpath
, &st
) && S_ISBLK(st
.st_mode
) && st
.st_rdev
== dev
)
1186 static int validate_device_btrfs(int pfd
, int dfd
)
1188 struct btrfs_ioctl_fs_info_args fsinfo
;
1189 static struct btrfs_ioctl_dev_info_args devinfo
;
1190 struct btrfs_super_block sb2
;
1192 if (ioctl(pfd
, BTRFS_IOC_FS_INFO
, &fsinfo
))
1195 /* We do not support multi-device btrfs yet */
1196 if (fsinfo
.num_devices
!= 1)
1199 /* The one device will have the max devid */
1200 memset(&devinfo
, 0, sizeof devinfo
);
1201 devinfo
.devid
= fsinfo
.max_id
;
1202 if (ioctl(pfd
, BTRFS_IOC_DEV_INFO
, &devinfo
))
1205 if (devinfo
.path
[0] != '/')
1208 if (xpread(dfd
, &sb2
, sizeof sb2
, BTRFS_SUPER_INFO_OFFSET
) != sizeof sb2
)
1211 if (memcmp(sb2
.magic
, BTRFS_MAGIC
, BTRFS_MAGIC_L
))
1214 if (memcmp(sb2
.fsid
, fsinfo
.fsid
, sizeof fsinfo
.fsid
))
1217 if (sb2
.num_devices
!= 1)
1220 if (sb2
.dev_item
.devid
!= devinfo
.devid
)
1223 if (memcmp(sb2
.dev_item
.uuid
, devinfo
.uuid
, sizeof devinfo
.uuid
))
1226 if (memcmp(sb2
.dev_item
.fsid
, fsinfo
.fsid
, sizeof fsinfo
.fsid
))
1229 return 0; /* It's good! */
1232 static const char *find_device_btrfs(const char *path
)
1235 struct btrfs_ioctl_fs_info_args fsinfo
;
1236 static struct btrfs_ioctl_dev_info_args devinfo
;
1237 const char *rv
= NULL
;
1241 pfd
= open(path
, O_RDONLY
);
1245 if (ioctl(pfd
, BTRFS_IOC_FS_INFO
, &fsinfo
))
1248 /* We do not support multi-device btrfs yet */
1249 if (fsinfo
.num_devices
!= 1)
1252 /* The one device will have the max devid */
1253 memset(&devinfo
, 0, sizeof devinfo
);
1254 devinfo
.devid
= fsinfo
.max_id
;
1255 if (ioctl(pfd
, BTRFS_IOC_DEV_INFO
, &devinfo
))
1258 if (devinfo
.path
[0] != '/')
1261 dfd
= open((const char *)devinfo
.path
, O_RDONLY
);
1265 if (!validate_device_btrfs(pfd
, dfd
))
1266 rv
= (const char *)devinfo
.path
; /* It's good! */
1276 static char *dupname(const char *name
)
1283 out
= strndup(name
, len
);
1287 static char *get_devname(const char *path
)
1289 char *devname
= NULL
;
1293 if (stat(path
, &st
) || !S_ISDIR(st
.st_mode
)) {
1294 fprintf(stderr
, "%s: Not a directory: %s\n", program
, path
);
1297 if (statfs(path
, &sfs
)) {
1298 fprintf(stderr
, "%s: statfs %s: %s\n", program
, path
, strerror(errno
));
1303 devname
= strdup(opt
.device
);
1306 if (fs_type
== BTRFS
) {
1307 /* For btrfs try to get the device name from btrfs itself */
1308 devname
= dupname(find_device_btrfs(path
));
1313 devname
= dupname(find_device_mountinfo(path
, st
.st_dev
));
1318 devname
= find_device_sysfs(st
.st_dev
);
1321 /* klibc doesn't have getmntent and friends; instead, just create
1322 a new device with the appropriate device type */
1323 snprintf(devname_buf
, sizeof devname_buf
, "/tmp/dev-%u:%u",
1324 major(st
.st_dev
), minor(st
.st_dev
));
1326 if (mknod(devname_buf
, S_IFBLK
| 0600, st
.st_dev
)) {
1327 fprintf(stderr
, "%s: cannot create device %s\n", program
, devname
);
1331 atexit(device_cleanup
); /* unlink the device node on exit */
1332 devname
= dupname(devname_buf
);
1337 devname
= find_device("/proc/mounts", st
.st_dev
);
1340 /* Didn't find it in /proc/mounts, try /etc/mtab */
1341 devname
= find_device("/etc/mtab", st
.st_dev
);
1344 devname
= find_device_sysfs(st
.st_dev
);
1346 fprintf(stderr
, "%s: cannot find device for path %s\n", program
, path
);
1350 fprintf(stderr
, "%s is device %s\n", path
, devname
);
1356 static int open_device(const char *path
, struct stat
*st
, char **_devname
)
1359 char *devname
= NULL
;
1363 if (stat(path
, st
) || !S_ISDIR(st
->st_mode
)) {
1364 fprintf(stderr
, "%s: Not a directory: %s\n", program
, path
);
1368 if (statfs(path
, &sfs
)) {
1369 fprintf(stderr
, "%s: statfs %s: %s\n", program
, path
, strerror(errno
));
1373 if (sfs
.f_type
== EXT2_SUPER_MAGIC
)
1375 else if (sfs
.f_type
== BTRFS_SUPER_MAGIC
)
1377 else if (sfs
.f_type
== MSDOS_SUPER_MAGIC
)
1379 else if (sfs
.f_type
== NTFS_SB_MAGIC
||
1380 sfs
.f_type
== FUSE_SUPER_MAGIC
/* ntfs-3g */)
1382 else if (sfs
.f_type
== XFS_SUPER_MAGIC
)
1384 else if (sfs
.f_type
== UFS1_SUPER_MAGIC
)
1386 else if (sfs
.f_type
== UFS2_SUPER_MAGIC
)
1391 "%s: not a fat, ntfs, ext2/3/4, btrfs, xfs or"
1392 "ufs1/2 filesystem: %s\n",
1398 devname
= get_devname(path
);
1400 if ((devfd
= open(devname
, O_RDWR
| O_SYNC
)) < 0) {
1401 fprintf(stderr
, "%s: cannot open device %s\n", program
, devname
);
1406 /* Verify that the device we opened is the device intended */
1407 if (validate_device(path
, devfd
)) {
1408 fprintf(stderr
, "%s: path %s doesn't match device %s\n",
1409 program
, path
, devname
);
1415 *_devname
= devname
;
1421 static int btrfs_read_adv(int devfd
)
1423 if (xpread(devfd
, syslinux_adv
, 2 * ADV_SIZE
, BTRFS_ADV_OFFSET
)
1427 return syslinux_validate_adv(syslinux_adv
) ? 1 : 0;
1430 static inline int xfs_read_adv(int devfd
)
1432 const size_t adv_size
= 2 * ADV_SIZE
;
1434 if (xpread(devfd
, syslinux_adv
, adv_size
, boot_image_len
) != adv_size
)
1437 return syslinux_validate_adv(syslinux_adv
) ? 1 : 0;
1440 static int ext_read_adv(const char *path
, int devfd
, const char **namep
)
1445 if (fs_type
== BTRFS
) {
1446 /* btrfs "ldlinux.sys" is in 64k blank area */
1447 return btrfs_read_adv(devfd
);
1448 } else if (fs_type
== XFS
) {
1449 /* XFS "ldlinux.sys" is in the first 2048 bytes of the primary AG */
1450 return xfs_read_adv(devfd
);
1452 err
= read_adv(path
, name
= "ldlinux.sys");
1453 if (err
== 2) /* ldlinux.sys does not exist */
1454 err
= read_adv(path
, name
= "extlinux.sys");
1461 static int ext_write_adv(const char *path
, const char *cfg
, int devfd
)
1463 if (fs_type
== BTRFS
) { /* btrfs "ldlinux.sys" is in 64k blank area */
1464 if (xpwrite(devfd
, syslinux_adv
, 2 * ADV_SIZE
,
1465 BTRFS_ADV_OFFSET
) != 2 * ADV_SIZE
) {
1466 perror("writing adv");
1471 return write_adv(path
, cfg
);
1474 static int install_loader(const char *path
, int update_only
)
1476 struct stat st
, fst
;
1478 char *devname
= NULL
;
1480 devfd
= open_device(path
, &st
, &devname
);
1484 if (update_only
&& !syslinux_already_installed(devfd
)) {
1485 fprintf(stderr
, "%s: no previous syslinux boot sector found\n",
1491 /* Read a pre-existing ADV, if already installed */
1492 if (opt
.reset_adv
) {
1493 syslinux_reset_adv(syslinux_adv
);
1494 } else if (ext_read_adv(path
, devfd
, NULL
) < 0) {
1499 if (modify_adv() < 0) {
1504 /* Install ldlinux.sys */
1505 if (install_file(path
, devfd
, &fst
)) {
1509 if (fst
.st_dev
!= st
.st_dev
) {
1510 fprintf(stderr
, "%s: file system changed under us - aborting!\n",
1517 rv
= install_bootblock(devfd
, devname
);
1526 * Modify the ADV of an existing installation
1528 int modify_existing_adv(const char *path
)
1530 const char *filename
;
1533 devfd
= open_device(path
, NULL
, NULL
);
1537 if (ext_read_adv(path
, devfd
, &filename
) < 0) {
1541 if (modify_adv() < 0) {
1545 if (ext_write_adv(path
, filename
, devfd
) < 0) {
1553 int main(int argc
, char *argv
[])
1555 parse_options(argc
, argv
, MODE_EXTLINUX
);
1557 if (!opt
.directory
|| opt
.install_mbr
|| opt
.activate_partition
)
1560 if (opt
.update_only
== -1) {
1561 if (opt
.reset_adv
|| opt
.set_once
|| opt
.menu_save
)
1562 return modify_existing_adv(opt
.directory
);
1564 usage(EX_USAGE
, MODE_EXTLINUX
);
1567 return install_loader(opt
.directory
, opt
.update_only
);