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 in the first 64K blank area, which
602 is not managed by btrfs tree, so actually this is not installed as a file,
603 since the cow feature of btrfs would move the ldlinux.sys file everywhere. */
604 int btrfs_install_file(const char *path
, int devfd
, struct stat
*rst
)
609 patch_file_and_bootblock(-1, path
, devfd
);
610 if (xpwrite(devfd
, (const char _force
*)boot_image
,
611 boot_image_len
, BTRFS_EXTLINUX_OFFSET
)
613 perror("writing bootblock");
616 dprintf("write boot_image to 0x%x\n", BTRFS_EXTLINUX_OFFSET
);
617 if (xpwrite(devfd
, syslinux_adv
, 2 * ADV_SIZE
, BTRFS_ADV_OFFSET
)
619 perror("writing adv");
622 dprintf("write adv to 0x%x\n", BTRFS_ADV_OFFSET
);
623 if (stat(path
, rst
)) {
629 * Note that we *can* install ldinux.c32 as a regular file because
630 * it doesn't need to be within the first 64K. The Syslinux core
631 * has enough smarts to search the btrfs dirs and find this file.
633 rv
= asprintf(&file
, "%s%sldlinux.c32",
634 path
, path
[0] && path
[strlen(path
) - 1] == '/' ? "" : "/");
635 if (rv
< 0 || !file
) {
640 fd
= open(file
, O_WRONLY
| O_TRUNC
| O_CREAT
| O_SYNC
,
641 S_IRUSR
| S_IRGRP
| S_IROTH
);
648 rv
= xpwrite(fd
, (const char _force
*)syslinux_ldlinuxc32
,
649 syslinux_ldlinuxc32_len
, 0);
650 if (rv
!= (int)syslinux_ldlinuxc32_len
) {
651 fprintf(stderr
, "%s: write failure on %s\n", program
, file
);
662 * Due to historical reasons (SGI IRIX's design of disk layouts), the first
663 * sector in the primary AG on XFS filesystems contains the superblock, which is
664 * a problem with bootloaders that rely on BIOSes (that load VBRs which are
665 * located in the first sector of the partition).
667 * Thus, we need to handle this issue, otherwise Syslinux will damage the XFS's
670 static int xfs_install_file(const char *path
, int devfd
, struct stat
*rst
)
672 static char file
[PATH_MAX
+ 1];
673 static char c32file
[PATH_MAX
+ 1];
678 snprintf(file
, PATH_MAX
+ 1, "%s%sldlinux.sys", path
,
679 path
[0] && path
[strlen(path
) - 1] == '/' ? "" : "/");
680 snprintf(c32file
, PATH_MAX
+ 1, "%s%sldlinux.c32", path
,
681 path
[0] && path
[strlen(path
) - 1] == '/' ? "" : "/");
683 dirfd
= open(path
, O_RDONLY
| O_DIRECTORY
);
689 fd
= open(file
, O_RDONLY
);
691 if (errno
!= ENOENT
) {
696 clear_attributes(fd
);
701 fd
= rewrite_boot_image(devfd
, path
, file
);
705 /* Attempt to set immutable flag and remove all write access */
706 /* Only set immutable flag if file is owned by root */
709 if (fstat(fd
, rst
)) {
720 fd
= open(c32file
, O_WRONLY
| O_TRUNC
| O_CREAT
| O_SYNC
,
721 S_IRUSR
| S_IRGRP
| S_IROTH
);
727 retval
= xpwrite(fd
, (const char _force
*)syslinux_ldlinuxc32
,
728 syslinux_ldlinuxc32_len
, 0);
729 if (retval
!= (int)syslinux_ldlinuxc32_len
) {
730 fprintf(stderr
, "%s: write failure on %s\n", program
, file
);
751 * * test if path is a subvolume:
752 * * this function return
753 * * 0-> path exists but it is not a subvolume
754 * * 1-> path exists and it is a subvolume
755 * * -1 -> path is unaccessible
757 static int test_issubvolume(char *path
)
763 res
= stat(path
, &st
);
767 return (st
.st_ino
== 256) && S_ISDIR(st
.st_mode
);
772 * Get the default subvolume of a btrfs filesystem
773 * rootdir: btrfs root dir
774 * subvol: this function will save the default subvolume name here
776 static char * get_default_subvol(char * rootdir
, char * subvol
)
778 struct btrfs_ioctl_search_args args
;
779 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
780 struct btrfs_ioctl_search_header
*sh
;
783 struct btrfs_root_ref
*ref
;
784 struct btrfs_dir_item
*dir_item
;
785 unsigned long off
= 0;
789 u64 defaultsubvolid
= 0;
791 ret
= test_issubvolume(rootdir
);
793 fd
= open(rootdir
, O_RDONLY
);
795 fprintf(stderr
, "ERROR: failed to open %s\n", rootdir
);
804 memset(&args
, 0, sizeof(args
));
806 /* search in the tree of tree roots */
810 * set the min and max to backref keys. The search will
811 * only send back this type of key now.
813 sk
->max_type
= BTRFS_DIR_ITEM_KEY
;
814 sk
->min_type
= BTRFS_DIR_ITEM_KEY
;
817 * set all the other params to the max, we'll take any objectid
820 sk
->min_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
821 sk
->max_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
823 sk
->max_offset
= (u64
)-1;
825 sk
->max_transid
= (u64
)-1;
827 /* just a big number, doesn't matter much */
831 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
833 fprintf(stderr
, "ERROR: can't perform the search\n");
837 /* the ioctl returns the number of item it found in nr_items */
838 if (sk
->nr_items
== 0) {
845 * for each item, pull the key out of the header and then
846 * read the root_ref item it contains
848 for (i
= 0; i
< sk
->nr_items
; i
++) {
849 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+ off
);
851 if (sh
->type
== BTRFS_DIR_ITEM_KEY
) {
852 dir_item
= (struct btrfs_dir_item
*)(args
.buf
+ off
);
853 name_len
= dir_item
->name_len
;
854 name
= (char *)(dir_item
+ 1);
857 /*add_root(&root_lookup, sh->objectid, sh->offset,
858 dir_id, name, name_len);*/
859 strncpy(dirname
, name
, name_len
);
860 dirname
[name_len
] = '\0';
861 if (strcmp(dirname
, "default") == 0) {
862 defaultsubvolid
= dir_item
->location
.objectid
;
869 * record the mins in sk so we can make sure the
870 * next search doesn't repeat this root
872 sk
->min_objectid
= sh
->objectid
;
873 sk
->min_type
= sh
->type
;
874 sk
->max_type
= sh
->type
;
875 sk
->min_offset
= sh
->offset
;
877 if (defaultsubvolid
!= 0)
880 /* this iteration is done, step forward one root for the next
883 if (sk
->min_objectid
< (u64
)-1) {
884 sk
->min_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
885 sk
->max_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
886 sk
->max_type
= BTRFS_ROOT_BACKREF_KEY
;
887 sk
->min_type
= BTRFS_ROOT_BACKREF_KEY
;
893 if (defaultsubvolid
== 0) {
898 memset(&args
, 0, sizeof(args
));
900 /* search in the tree of tree roots */
904 * set the min and max to backref keys. The search will
905 * only send back this type of key now.
907 sk
->max_type
= BTRFS_ROOT_BACKREF_KEY
;
908 sk
->min_type
= BTRFS_ROOT_BACKREF_KEY
;
911 * set all the other params to the max, we'll take any objectid
914 sk
->max_objectid
= (u64
)-1;
915 sk
->max_offset
= (u64
)-1;
916 sk
->max_transid
= (u64
)-1;
918 /* just a big number, doesn't matter much */
922 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
924 fprintf(stderr
, "ERROR: can't perform the search\n");
928 /* the ioctl returns the number of item it found in nr_items */
929 if (sk
->nr_items
== 0)
935 * for each item, pull the key out of the header and then
936 * read the root_ref item it contains
938 for (i
= 0; i
< sk
->nr_items
; i
++) {
939 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+ off
);
941 if (sh
->type
== BTRFS_ROOT_BACKREF_KEY
) {
942 ref
= (struct btrfs_root_ref
*)(args
.buf
+ off
);
943 name_len
= ref
->name_len
;
944 name
= (char *)(ref
+ 1);
946 if (sh
->objectid
== defaultsubvolid
) {
947 strncpy(subvol
, name
, name_len
);
948 subvol
[name_len
] = '\0';
949 dprintf("The default subvolume: %s, ID: %llu\n",
950 subvol
, sh
->objectid
);
959 * record the mins in sk so we can make sure the
960 * next search doesn't repeat this root
962 sk
->min_objectid
= sh
->objectid
;
963 sk
->min_type
= sh
->type
;
964 sk
->min_offset
= sh
->offset
;
966 if (subvol
[0] != '\0')
969 /* this iteration is done, step forward one root for the next
972 if (sk
->min_objectid
< (u64
)-1) {
974 sk
->min_type
= BTRFS_ROOT_BACKREF_KEY
;
982 static int install_file(const char *path
, int devfd
, struct stat
*rst
)
984 if (fs_type
== EXT2
|| fs_type
== VFAT
|| fs_type
== NTFS
985 || fs_type
== UFS1
|| fs_type
== UFS2
)
986 return ext2_fat_install_file(path
, devfd
, rst
);
987 else if (fs_type
== BTRFS
)
988 return btrfs_install_file(path
, devfd
, rst
);
989 else if (fs_type
== XFS
)
990 return xfs_install_file(path
, devfd
, rst
);
996 static char devname_buf
[64];
998 static void device_cleanup(void)
1000 unlink(devname_buf
);
1004 /* Verify that a device fd and a pathname agree.
1005 Return 0 on valid, -1 on error. */
1006 static int validate_device_btrfs(int pathfd
, int devfd
);
1007 static int validate_device(const char *path
, int devfd
)
1009 struct stat pst
, dst
;
1014 pfd
= open(path
, O_RDONLY
|O_DIRECTORY
);
1018 if (fstat(pfd
, &pst
) || fstat(devfd
, &dst
) || statfs(path
, &sfs
))
1021 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
1022 if (fs_type
== BTRFS
) {
1023 if (sfs
.f_type
== BTRFS_SUPER_MAGIC
)
1024 rv
= validate_device_btrfs(pfd
, devfd
);
1026 rv
= (pst
.st_dev
== dst
.st_rdev
) ? 0 : -1;
1036 static char *find_device(const char *mtab_file
, dev_t dev
)
1041 char *devname
= NULL
;
1044 mtab
= setmntent(mtab_file
, "r");
1049 while ((mnt
= getmntent(mtab
))) {
1050 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
1053 if (!strcmp(mnt
->mnt_type
, "btrfs") &&
1054 !stat(mnt
->mnt_dir
, &dst
) &&
1055 dst
.st_dev
== dev
) {
1057 get_default_subvol(mnt
->mnt_dir
, subvol
);
1062 if ((!strcmp(mnt
->mnt_type
, "ext2") ||
1063 !strcmp(mnt
->mnt_type
, "ext3") ||
1064 !strcmp(mnt
->mnt_type
, "ext4")) &&
1065 !stat(mnt
->mnt_fsname
, &dst
) &&
1066 dst
.st_rdev
== dev
) {
1071 if ((!strcmp(mnt
->mnt_type
, "vfat")) &&
1072 !stat(mnt
->mnt_fsname
, &dst
) &&
1073 dst
.st_rdev
== dev
) {
1078 if ((!strcmp(mnt
->mnt_type
, "fuseblk") /* ntfs-3g */ ||
1079 !strcmp(mnt
->mnt_type
, "ntfs")) &&
1080 !stat(mnt
->mnt_fsname
, &dst
) &&
1081 dst
.st_rdev
== dev
) {
1088 if (!strcmp(mnt
->mnt_type
, "xfs") && !stat(mnt
->mnt_fsname
, &dst
) &&
1089 dst
.st_rdev
== dev
) {
1097 if (!strcmp(mnt
->mnt_type
, "ufs") && !stat(mnt
->mnt_fsname
, &dst
) &&
1098 dst
.st_rdev
== dev
) {
1108 devname
= strdup(mnt
->mnt_fsname
);
1120 * On newer Linux kernels we can use sysfs to get a backwards mapping
1121 * from device names to standard filenames
1123 static char *find_device_sysfs(dev_t dev
)
1126 char linkname
[PATH_MAX
];
1132 snprintf(sysname
, sizeof sysname
, "/sys/dev/block/%u:%u",
1133 major(dev
), minor(dev
));
1135 llen
= readlink(sysname
, linkname
, sizeof linkname
);
1136 if (llen
< 0 || llen
>= sizeof linkname
)
1139 linkname
[llen
] = '\0';
1141 p
= strrchr(linkname
, '/');
1142 p
= p
? p
+1 : linkname
; /* Leave basename */
1144 buf
= q
= malloc(strlen(p
) + 6);
1148 memcpy(q
, "/dev/", 5);
1152 *q
++ = (*p
== '!') ? '/' : *p
;
1158 if (!stat(buf
, &st
) && st
.st_dev
== dev
)
1159 return buf
; /* Found it! */
1167 static const char *find_device_mountinfo(const char *path
, dev_t dev
)
1169 const struct mountinfo
*m
;
1172 m
= find_mount(path
, NULL
);
1176 if (m
->devpath
[0] == '/' && m
->dev
== dev
&&
1177 !stat(m
->devpath
, &st
) && S_ISBLK(st
.st_mode
) && st
.st_rdev
== dev
)
1183 static int validate_device_btrfs(int pfd
, int dfd
)
1185 struct btrfs_ioctl_fs_info_args fsinfo
;
1186 static struct btrfs_ioctl_dev_info_args devinfo
;
1187 struct btrfs_super_block sb2
;
1189 if (ioctl(pfd
, BTRFS_IOC_FS_INFO
, &fsinfo
))
1192 /* We do not support multi-device btrfs yet */
1193 if (fsinfo
.num_devices
!= 1)
1196 /* The one device will have the max devid */
1197 memset(&devinfo
, 0, sizeof devinfo
);
1198 devinfo
.devid
= fsinfo
.max_id
;
1199 if (ioctl(pfd
, BTRFS_IOC_DEV_INFO
, &devinfo
))
1202 if (devinfo
.path
[0] != '/')
1205 if (xpread(dfd
, &sb2
, sizeof sb2
, BTRFS_SUPER_INFO_OFFSET
) != sizeof sb2
)
1208 if (memcmp(sb2
.magic
, BTRFS_MAGIC
, BTRFS_MAGIC_L
))
1211 if (memcmp(sb2
.fsid
, fsinfo
.fsid
, sizeof fsinfo
.fsid
))
1214 if (sb2
.num_devices
!= 1)
1217 if (sb2
.dev_item
.devid
!= devinfo
.devid
)
1220 if (memcmp(sb2
.dev_item
.uuid
, devinfo
.uuid
, sizeof devinfo
.uuid
))
1223 if (memcmp(sb2
.dev_item
.fsid
, fsinfo
.fsid
, sizeof fsinfo
.fsid
))
1226 return 0; /* It's good! */
1229 static const char *find_device_btrfs(const char *path
)
1232 struct btrfs_ioctl_fs_info_args fsinfo
;
1233 static struct btrfs_ioctl_dev_info_args devinfo
;
1234 const char *rv
= NULL
;
1238 pfd
= open(path
, O_RDONLY
);
1242 if (ioctl(pfd
, BTRFS_IOC_FS_INFO
, &fsinfo
))
1245 /* We do not support multi-device btrfs yet */
1246 if (fsinfo
.num_devices
!= 1)
1249 /* The one device will have the max devid */
1250 memset(&devinfo
, 0, sizeof devinfo
);
1251 devinfo
.devid
= fsinfo
.max_id
;
1252 if (ioctl(pfd
, BTRFS_IOC_DEV_INFO
, &devinfo
))
1255 if (devinfo
.path
[0] != '/')
1258 dfd
= open((const char *)devinfo
.path
, O_RDONLY
);
1262 if (!validate_device_btrfs(pfd
, dfd
))
1263 rv
= (const char *)devinfo
.path
; /* It's good! */
1273 static char *dupname(const char *name
)
1280 out
= strndup(name
, len
);
1284 static char *get_devname(const char *path
)
1286 char *devname
= NULL
;
1290 if (stat(path
, &st
) || !S_ISDIR(st
.st_mode
)) {
1291 fprintf(stderr
, "%s: Not a directory: %s\n", program
, path
);
1294 if (statfs(path
, &sfs
)) {
1295 fprintf(stderr
, "%s: statfs %s: %s\n", program
, path
, strerror(errno
));
1300 devname
= strdup(opt
.device
);
1303 if (fs_type
== BTRFS
) {
1304 /* For btrfs try to get the device name from btrfs itself */
1305 devname
= dupname(find_device_btrfs(path
));
1310 devname
= dupname(find_device_mountinfo(path
, st
.st_dev
));
1315 devname
= find_device_sysfs(st
.st_dev
);
1318 /* klibc doesn't have getmntent and friends; instead, just create
1319 a new device with the appropriate device type */
1320 snprintf(devname_buf
, sizeof devname_buf
, "/tmp/dev-%u:%u",
1321 major(st
.st_dev
), minor(st
.st_dev
));
1323 if (mknod(devname_buf
, S_IFBLK
| 0600, st
.st_dev
)) {
1324 fprintf(stderr
, "%s: cannot create device %s\n", program
, devname
);
1328 atexit(device_cleanup
); /* unlink the device node on exit */
1329 devname
= dupname(devname_buf
);
1334 devname
= find_device("/proc/mounts", st
.st_dev
);
1337 /* Didn't find it in /proc/mounts, try /etc/mtab */
1338 devname
= find_device("/etc/mtab", st
.st_dev
);
1341 devname
= find_device_sysfs(st
.st_dev
);
1343 fprintf(stderr
, "%s: cannot find device for path %s\n", program
, path
);
1347 fprintf(stderr
, "%s is device %s\n", path
, devname
);
1353 static int open_device(const char *path
, struct stat
*st
, char **_devname
)
1356 char *devname
= NULL
;
1360 if (stat(path
, st
) || !S_ISDIR(st
->st_mode
)) {
1361 fprintf(stderr
, "%s: Not a directory: %s\n", program
, path
);
1365 if (statfs(path
, &sfs
)) {
1366 fprintf(stderr
, "%s: statfs %s: %s\n", program
, path
, strerror(errno
));
1370 if (sfs
.f_type
== EXT2_SUPER_MAGIC
)
1372 else if (sfs
.f_type
== BTRFS_SUPER_MAGIC
)
1374 else if (sfs
.f_type
== MSDOS_SUPER_MAGIC
)
1376 else if (sfs
.f_type
== NTFS_SB_MAGIC
||
1377 sfs
.f_type
== FUSE_SUPER_MAGIC
/* ntfs-3g */)
1379 else if (sfs
.f_type
== XFS_SUPER_MAGIC
)
1381 else if (sfs
.f_type
== UFS1_SUPER_MAGIC
)
1383 else if (sfs
.f_type
== UFS2_SUPER_MAGIC
)
1388 "%s: not a fat, ntfs, ext2/3/4, btrfs, xfs or"
1389 "ufs1/2 filesystem: %s\n",
1395 devname
= get_devname(path
);
1397 if ((devfd
= open(devname
, O_RDWR
| O_SYNC
)) < 0) {
1398 fprintf(stderr
, "%s: cannot open device %s\n", program
, devname
);
1403 /* Verify that the device we opened is the device intended */
1404 if (validate_device(path
, devfd
)) {
1405 fprintf(stderr
, "%s: path %s doesn't match device %s\n",
1406 program
, path
, devname
);
1412 *_devname
= devname
;
1418 static int btrfs_read_adv(int devfd
)
1420 if (xpread(devfd
, syslinux_adv
, 2 * ADV_SIZE
, BTRFS_ADV_OFFSET
)
1424 return syslinux_validate_adv(syslinux_adv
) ? 1 : 0;
1427 static inline int xfs_read_adv(int devfd
)
1429 const size_t adv_size
= 2 * ADV_SIZE
;
1431 if (xpread(devfd
, syslinux_adv
, adv_size
, boot_image_len
) != adv_size
)
1434 return syslinux_validate_adv(syslinux_adv
) ? 1 : 0;
1437 static int ext_read_adv(const char *path
, int devfd
, const char **namep
)
1442 if (fs_type
== BTRFS
) {
1443 /* btrfs "ldlinux.sys" is in 64k blank area */
1444 return btrfs_read_adv(devfd
);
1445 } else if (fs_type
== XFS
) {
1446 /* XFS "ldlinux.sys" is in the first 2048 bytes of the primary AG */
1447 return xfs_read_adv(devfd
);
1449 err
= read_adv(path
, name
= "ldlinux.sys");
1450 if (err
== 2) /* ldlinux.sys does not exist */
1451 err
= read_adv(path
, name
= "extlinux.sys");
1458 static int ext_write_adv(const char *path
, const char *cfg
, int devfd
)
1460 if (fs_type
== BTRFS
) { /* btrfs "ldlinux.sys" is in 64k blank area */
1461 if (xpwrite(devfd
, syslinux_adv
, 2 * ADV_SIZE
,
1462 BTRFS_ADV_OFFSET
) != 2 * ADV_SIZE
) {
1463 perror("writing adv");
1468 return write_adv(path
, cfg
);
1471 static int install_loader(const char *path
, int update_only
)
1473 struct stat st
, fst
;
1475 char *devname
= NULL
;
1477 devfd
= open_device(path
, &st
, &devname
);
1481 if (update_only
&& !syslinux_already_installed(devfd
)) {
1482 fprintf(stderr
, "%s: no previous syslinux boot sector found\n",
1488 /* Read a pre-existing ADV, if already installed */
1489 if (opt
.reset_adv
) {
1490 syslinux_reset_adv(syslinux_adv
);
1491 } else if (ext_read_adv(path
, devfd
, NULL
) < 0) {
1496 if (modify_adv() < 0) {
1501 /* Install ldlinux.sys */
1502 if (install_file(path
, devfd
, &fst
)) {
1506 if (fst
.st_dev
!= st
.st_dev
) {
1507 fprintf(stderr
, "%s: file system changed under us - aborting!\n",
1514 rv
= install_bootblock(devfd
, devname
);
1523 * Modify the ADV of an existing installation
1525 int modify_existing_adv(const char *path
)
1527 const char *filename
;
1530 devfd
= open_device(path
, NULL
, NULL
);
1534 if (ext_read_adv(path
, devfd
, &filename
) < 0) {
1538 if (modify_adv() < 0) {
1542 if (ext_write_adv(path
, filename
, devfd
) < 0) {
1550 int main(int argc
, char *argv
[])
1552 parse_options(argc
, argv
, MODE_EXTLINUX
);
1554 if (!opt
.directory
|| opt
.install_mbr
|| opt
.activate_partition
)
1557 if (opt
.update_only
== -1) {
1558 if (opt
.reset_adv
|| opt
.set_once
|| opt
.menu_save
)
1559 return modify_existing_adv(opt
.directory
);
1561 usage(EX_USAGE
, MODE_EXTLINUX
);
1564 return install_loader(opt
.directory
, opt
.update_only
);