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 an 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 */
61 #include "syslxopt.h" /* unified options */
62 #include "mountinfo.h"
65 # define dprintf printf
67 # define dprintf(...) ((void)0)
70 #ifndef EXT2_SUPER_OFFSET
71 #define EXT2_SUPER_OFFSET 1024
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
78 #define XFS_BOOTSECT_OFFSET (4 << SECTOR_SHIFT)
79 #define XFS_SUPPORTED_BLOCKSIZE 4096 /* 4 KiB filesystem block size */
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".
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
];
91 #define BTRFS_ADV_OFFSET (BTRFS_BOOT_AREA_A_OFFSET + BTRFS_BOOT_AREA_A_SIZE \
95 * Get the size of a block device
97 static uint64_t get_size(int devfd
)
104 if (!ioctl(devfd
, BLKGETSIZE64
, &bytes
))
107 if (!ioctl(devfd
, BLKGETSIZE
, §s
))
108 return (uint64_t) sects
<< 9;
109 else if (!fstat(devfd
, &st
) && st
.st_size
)
116 * Get device geometry and partition offset
118 struct geometry_table
{
120 struct hd_geometry g
;
123 static int sysfs_get_offset(int devfd
, unsigned long *start
)
126 char sysfs_name
[128];
130 if (fstat(devfd
, &st
))
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
)
139 f
= fopen(sysfs_name
, "r");
143 rv
= fscanf(f
, "%lu", start
);
146 return (rv
== 1) ? 0 : -1;
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 */
166 int get_geometry(int devfd
, uint64_t totalbytes
, struct hd_geometry
*geo
)
168 struct floppy_struct fd_str
;
170 struct loop_info64 li64
;
171 const struct geometry_table
*gp
;
174 memset(geo
, 0, sizeof *geo
);
176 if (!ioctl(devfd
, HDIO_GETGEO
, geo
)) {
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
;
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
);
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. */
198 geo
->heads
= opt
.heads
? : 64;
199 geo
->sectors
= opt
.sectors
? : 32;
200 geo
->cylinders
= totalbytes
/ (geo
->heads
* geo
->sectors
<< SECTOR_SHIFT
);
203 if (!opt
.sectors
&& !opt
.heads
) {
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 */
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
)) {
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.
229 * Returns the number of modified bytes in the boot file.
231 static int patch_file_and_bootblock(int fd
, const char *dir
, int devfd
)
233 struct stat dirst
, xdst
;
234 struct hd_geometry geo
;
236 uint64_t totalbytes
, totalsectors
;
238 struct fat_boot_sector
*sbs
;
239 char *dirpath
, *subpath
, *xdirpath
;
242 dirpath
= realpath(dir
, NULL
);
243 if (!dirpath
|| stat(dir
, &dirst
)) {
244 perror("accessing install directory");
245 exit(255); /* This should never happen */
248 if (lstat(dirpath
, &xdst
) ||
249 dirst
.st_ino
!= xdst
.st_ino
||
250 dirst
.st_dev
!= xdst
.st_dev
) {
251 perror("realpath returned nonsense");
255 subpath
= strchr(dirpath
, '\0');
257 if (*subpath
== '/') {
258 if (subpath
> dirpath
) {
264 if (lstat(xdirpath
, &xdst
) || dirst
.st_dev
!= xdst
.st_dev
) {
265 subpath
= strchr(subpath
+1, '/');
267 subpath
= "/"; /* It's the root of the filesystem */
273 if (subpath
== dirpath
)
279 /* Now subpath should contain the path relative to the fs base */
280 dprintf("subpath = %s\n", subpath
);
282 totalbytes
= get_size(devfd
);
283 get_geometry(devfd
, totalbytes
, &geo
);
286 geo
.heads
= opt
.heads
;
288 geo
.sectors
= opt
.sectors
;
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
);
295 sbs
= (struct fat_boot_sector
*)syslinux_bootsect
;
297 totalsectors
= totalbytes
>> SECTOR_SHIFT
;
298 if (totalsectors
>= 65536) {
299 set_16(&sbs
->bsSectors
, 0);
301 set_16(&sbs
->bsSectors
, totalsectors
);
303 set_32(&sbs
->bsHugeSectors
, totalsectors
);
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
);
310 /* Construct the boot file map */
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
)) {
322 } else if (fs_type
== BTRFS
) {
324 sector_t
*sp
= sectp
;
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
;
332 /* Create the modified image in memory */
333 rv
= syslinux_patch(sectp
, nsect
, opt
.stupid_mode
,
334 opt
.raid_mode
, subpath
, subvol
);
341 * Install the boot block on the specified device.
342 * Must be run AFTER install_file()!
344 int install_bootblock(int fd
, const char *device
)
346 struct ext2_super_block sb
;
347 struct btrfs_super_block sb2
;
348 struct fat_boot_sector sb3
;
349 struct ntfs_boot_sector sb4
;
351 struct ufs_super_block sb6
;
354 if (fs_type
== EXT2
) {
355 if (xpread(fd
, &sb
, sizeof sb
, EXT2_SUPER_OFFSET
) != sizeof sb
) {
356 perror("reading superblock");
360 if (sb
.s_magic
== EXT2_SUPER_MAGIC
)
362 } else if (fs_type
== BTRFS
) {
363 if (xpread(fd
, &sb2
, sizeof sb2
, BTRFS_SUPER_INFO_OFFSET
)
365 perror("reading superblock");
368 if (!memcmp(sb2
.magic
, BTRFS_MAGIC
, BTRFS_MAGIC_L
))
370 } else if (fs_type
== VFAT
) {
371 if (xpread(fd
, &sb3
, sizeof sb3
, 0) != sizeof sb3
) {
372 perror("reading fat superblock");
376 if (fat_check_sb_fields(&sb3
))
378 } else if (fs_type
== NTFS
) {
379 if (xpread(fd
, &sb4
, sizeof(sb4
), 0) != sizeof(sb4
)) {
380 perror("reading ntfs superblock");
384 if (ntfs_check_sb_fields(&sb4
))
386 } else if (fs_type
== XFS
) {
387 if (xpread(fd
, &sb5
, sizeof sb5
, 0) != sizeof sb5
) {
388 perror("reading xfs superblock");
392 if (sb5
.sb_magicnum
== *(u32
*)XFS_SB_MAGIC
) {
393 if (be32_to_cpu(sb5
.sb_blocksize
) != XFS_SUPPORTED_BLOCKSIZE
) {
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");
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
;
411 if (xpread(fd
, &sb6
, sizeof sb6
, sblock_off
) != sizeof sb6
) {
412 perror("reading superblock");
416 if (sb6
.fs_magic
== ufs_smagic
)
422 "no fat, ntfs, ext2/3/4, btrfs, xfs "
423 "or ufs1/2 superblock found on %s\n",
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");
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");
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");
454 if (xpwrite(fd
, syslinux_bootsect
, syslinux_bootsect_len
, 0)
455 != syslinux_bootsect_len
) {
456 perror("writing bootblock");
464 static int rewrite_boot_image(int devfd
, const char *path
, const char *filename
)
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
);
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");
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
);
492 /* Map the file, and patch the initial sector accordingly */
493 modbytes
= patch_file_and_bootblock(fd
, path
, devfd
);
495 /* Write the patch area again - this relies on the file being overwritten
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
);
511 int ext2_fat_install_file(const char *path
, int devfd
, struct stat
*rst
)
513 char *file
, *oldfile
, *c32file
;
514 int fd
= -1, dirfd
= -1;
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
) {
528 dirfd
= open(path
, O_RDONLY
| O_DIRECTORY
);
534 fd
= open(file
, O_RDONLY
);
536 if (errno
!= ENOENT
) {
541 clear_attributes(fd
);
545 fd
= rewrite_boot_image(devfd
, path
, file
);
549 /* Attempt to set immutable flag and remove all write access */
550 /* Only set immutable flag if file is owned by root */
553 if (fstat(fd
, rst
)) {
561 /* Look if we have the old filename */
562 fd
= open(oldfile
, O_RDONLY
);
564 clear_attributes(fd
);
569 fd
= open(c32file
, O_WRONLY
| O_TRUNC
| O_CREAT
| O_SYNC
,
570 S_IRUSR
| S_IRGRP
| S_IROTH
);
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
);
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
)
608 patch_file_and_bootblock(-1, path
, devfd
);
609 if (xpwrite(devfd
, (const char _force
*)boot_image
,
610 boot_image_len
, BTRFS_EXTLINUX_OFFSET
)
612 perror("writing bootblock");
615 dprintf("write boot_image to 0x%x\n", BTRFS_EXTLINUX_OFFSET
);
616 if (xpwrite(devfd
, syslinux_adv
, 2 * ADV_SIZE
, BTRFS_ADV_OFFSET
)
618 perror("writing adv");
621 dprintf("write adv to 0x%x\n", BTRFS_ADV_OFFSET
);
622 if (stat(path
, rst
)) {
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.
632 rv
= asprintf(&file
, "%s%sldlinux.c32",
633 path
, path
[0] && path
[strlen(path
) - 1] == '/' ? "" : "/");
634 if (rv
< 0 || !file
) {
639 fd
= open(file
, O_WRONLY
| O_TRUNC
| O_CREAT
| O_SYNC
,
640 S_IRUSR
| S_IRGRP
| S_IROTH
);
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
);
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).
666 * Thus, we need to handle this issue, otherwise Syslinux will damage the XFS's
669 static int xfs_install_file(const char *path
, int devfd
, struct stat
*rst
)
671 static char file
[PATH_MAX
+ 1];
672 static char c32file
[PATH_MAX
+ 1];
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] == '/' ? "" : "/");
682 dirfd
= open(path
, O_RDONLY
| O_DIRECTORY
);
688 fd
= open(file
, O_RDONLY
);
690 if (errno
!= ENOENT
) {
695 clear_attributes(fd
);
700 fd
= rewrite_boot_image(devfd
, path
, file
);
704 /* Attempt to set immutable flag and remove all write access */
705 /* Only set immutable flag if file is owned by root */
708 if (fstat(fd
, rst
)) {
719 fd
= open(c32file
, O_WRONLY
| O_TRUNC
| O_CREAT
| O_SYNC
,
720 S_IRUSR
| S_IRGRP
| S_IROTH
);
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
);
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
756 static int test_issubvolume(char *path
)
762 res
= stat(path
, &st
);
766 return (st
.st_ino
== 256) && S_ISDIR(st
.st_mode
);
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
775 static char * get_default_subvol(char * rootdir
, char * subvol
)
777 struct btrfs_ioctl_search_args args
;
778 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
779 struct btrfs_ioctl_search_header
*sh
;
782 struct btrfs_root_ref
*ref
;
783 struct btrfs_dir_item
*dir_item
;
784 unsigned long off
= 0;
788 u64 defaultsubvolid
= 0;
790 ret
= test_issubvolume(rootdir
);
792 fd
= open(rootdir
, O_RDONLY
);
794 fprintf(stderr
, "ERROR: failed to open %s\n", rootdir
);
803 memset(&args
, 0, sizeof(args
));
805 /* search in the tree of tree roots */
809 * set the min and max to backref keys. The search will
810 * only send back this type of key now.
812 sk
->max_type
= BTRFS_DIR_ITEM_KEY
;
813 sk
->min_type
= BTRFS_DIR_ITEM_KEY
;
816 * set all the other params to the max, we'll take any objectid
819 sk
->min_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
820 sk
->max_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
822 sk
->max_offset
= (u64
)-1;
824 sk
->max_transid
= (u64
)-1;
826 /* just a big number, doesn't matter much */
830 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
832 fprintf(stderr
, "ERROR: can't perform the search\n");
836 /* the ioctl returns the number of item it found in nr_items */
837 if (sk
->nr_items
== 0) {
844 * for each item, pull the key out of the header and then
845 * read the root_ref item it contains
847 for (i
= 0; i
< sk
->nr_items
; i
++) {
848 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+ off
);
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);
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
;
868 * record the mins in sk so we can make sure the
869 * next search doesn't repeat this root
871 sk
->min_objectid
= sh
->objectid
;
872 sk
->min_type
= sh
->type
;
873 sk
->max_type
= sh
->type
;
874 sk
->min_offset
= sh
->offset
;
876 if (defaultsubvolid
!= 0)
879 /* this iteration is done, step forward one root for the next
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
;
892 if (defaultsubvolid
== 0) {
897 memset(&args
, 0, sizeof(args
));
899 /* search in the tree of tree roots */
903 * set the min and max to backref keys. The search will
904 * only send back this type of key now.
906 sk
->max_type
= BTRFS_ROOT_BACKREF_KEY
;
907 sk
->min_type
= BTRFS_ROOT_BACKREF_KEY
;
910 * set all the other params to the max, we'll take any objectid
913 sk
->max_objectid
= (u64
)-1;
914 sk
->max_offset
= (u64
)-1;
915 sk
->max_transid
= (u64
)-1;
917 /* just a big number, doesn't matter much */
921 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
923 fprintf(stderr
, "ERROR: can't perform the search\n");
927 /* the ioctl returns the number of item it found in nr_items */
928 if (sk
->nr_items
== 0)
934 * for each item, pull the key out of the header and then
935 * read the root_ref item it contains
937 for (i
= 0; i
< sk
->nr_items
; i
++) {
938 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+ off
);
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);
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
);
958 * record the mins in sk so we can make sure the
959 * next search doesn't repeat this root
961 sk
->min_objectid
= sh
->objectid
;
962 sk
->min_type
= sh
->type
;
963 sk
->min_offset
= sh
->offset
;
965 if (subvol
[0] != '\0')
968 /* this iteration is done, step forward one root for the next
971 if (sk
->min_objectid
< (u64
)-1) {
973 sk
->min_type
= BTRFS_ROOT_BACKREF_KEY
;
981 static int install_file(const char *path
, int devfd
, struct stat
*rst
)
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
);
995 static char devname_buf
[64];
997 static void device_cleanup(void)
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
)
1008 struct stat pst
, dst
;
1013 pfd
= open(path
, O_RDONLY
|O_DIRECTORY
);
1017 if (fstat(pfd
, &pst
) || fstat(devfd
, &dst
) || statfs(path
, &sfs
))
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
);
1025 rv
= (pst
.st_dev
== dst
.st_rdev
) ? 0 : -1;
1035 static const char *find_device(const char *mtab_file
, dev_t dev
)
1040 const char *devname
= NULL
;
1043 mtab
= setmntent(mtab_file
, "r");
1048 while ((mnt
= getmntent(mtab
))) {
1049 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
1052 if (!strcmp(mnt
->mnt_type
, "btrfs") &&
1053 !stat(mnt
->mnt_dir
, &dst
) &&
1054 dst
.st_dev
== dev
) {
1056 get_default_subvol(mnt
->mnt_dir
, subvol
);
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
) {
1070 if ((!strcmp(mnt
->mnt_type
, "vfat")) &&
1071 !stat(mnt
->mnt_fsname
, &dst
) &&
1072 dst
.st_rdev
== dev
) {
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
) {
1087 if (!strcmp(mnt
->mnt_type
, "xfs") && !stat(mnt
->mnt_fsname
, &dst
) &&
1088 dst
.st_rdev
== dev
) {
1096 if (!strcmp(mnt
->mnt_type
, "ufs") && !stat(mnt
->mnt_fsname
, &dst
) &&
1097 dst
.st_rdev
== dev
) {
1107 devname
= strdup(mnt
->mnt_fsname
);
1119 * On newer Linux kernels we can use sysfs to get a backwards mapping
1120 * from device names to standard filenames
1122 static const char *find_device_sysfs(dev_t dev
)
1125 char linkname
[PATH_MAX
];
1131 snprintf(sysname
, sizeof sysname
, "/sys/dev/block/%u:%u",
1132 major(dev
), minor(dev
));
1134 llen
= readlink(sysname
, linkname
, sizeof linkname
);
1135 if (llen
< 0 || llen
>= sizeof linkname
)
1138 linkname
[llen
] = '\0';
1140 p
= strrchr(linkname
, '/');
1141 p
= p
? p
+1 : linkname
; /* Leave basename */
1143 buf
= q
= malloc(strlen(p
) + 6);
1147 memcpy(q
, "/dev/", 5);
1151 *q
++ = (*p
== '!') ? '/' : *p
;
1157 if (!stat(buf
, &st
) && st
.st_dev
== dev
)
1158 return buf
; /* Found it! */
1166 static const char *find_device_mountinfo(const char *path
, dev_t dev
)
1168 const struct mountinfo
*m
;
1171 m
= find_mount(path
, NULL
);
1175 if (m
->devpath
[0] == '/' && m
->dev
== dev
&&
1176 !stat(m
->devpath
, &st
) && S_ISBLK(st
.st_mode
) && st
.st_rdev
== dev
)
1182 static int validate_device_btrfs(int pfd
, int dfd
)
1184 struct btrfs_ioctl_fs_info_args fsinfo
;
1185 static struct btrfs_ioctl_dev_info_args devinfo
;
1186 struct btrfs_super_block sb2
;
1188 if (ioctl(pfd
, BTRFS_IOC_FS_INFO
, &fsinfo
))
1191 /* We do not support multi-device btrfs yet */
1192 if (fsinfo
.num_devices
!= 1)
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
))
1201 if (devinfo
.path
[0] != '/')
1204 if (xpread(dfd
, &sb2
, sizeof sb2
, BTRFS_SUPER_INFO_OFFSET
) != sizeof sb2
)
1207 if (memcmp(sb2
.magic
, BTRFS_MAGIC
, BTRFS_MAGIC_L
))
1210 if (memcmp(sb2
.fsid
, fsinfo
.fsid
, sizeof fsinfo
.fsid
))
1213 if (sb2
.num_devices
!= 1)
1216 if (sb2
.dev_item
.devid
!= devinfo
.devid
)
1219 if (memcmp(sb2
.dev_item
.uuid
, devinfo
.uuid
, sizeof devinfo
.uuid
))
1222 if (memcmp(sb2
.dev_item
.fsid
, fsinfo
.fsid
, sizeof fsinfo
.fsid
))
1225 return 0; /* It's good! */
1228 static const char *find_device_btrfs(const char *path
)
1231 struct btrfs_ioctl_fs_info_args fsinfo
;
1232 static struct btrfs_ioctl_dev_info_args devinfo
;
1233 const char *rv
= NULL
;
1237 pfd
= open(path
, O_RDONLY
);
1241 if (ioctl(pfd
, BTRFS_IOC_FS_INFO
, &fsinfo
))
1244 /* We do not support multi-device btrfs yet */
1245 if (fsinfo
.num_devices
!= 1)
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
))
1254 if (devinfo
.path
[0] != '/')
1257 dfd
= open((const char *)devinfo
.path
, O_RDONLY
);
1261 if (!validate_device_btrfs(pfd
, dfd
))
1262 rv
= (const char *)devinfo
.path
; /* It's good! */
1272 static const char *get_devname(const char *path
)
1274 const char *devname
= NULL
;
1278 if (stat(path
, &st
) || !S_ISDIR(st
.st_mode
)) {
1279 fprintf(stderr
, "%s: Not a directory: %s\n", program
, path
);
1282 if (statfs(path
, &sfs
)) {
1283 fprintf(stderr
, "%s: statfs %s: %s\n", program
, path
, strerror(errno
));
1288 devname
= opt
.device
;
1291 if (fs_type
== BTRFS
) {
1292 /* For btrfs try to get the device name from btrfs itself */
1293 devname
= find_device_btrfs(path
);
1298 devname
= find_device_mountinfo(path
, st
.st_dev
);
1303 devname
= find_device_sysfs(st
.st_dev
);
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
));
1311 if (mknod(devname_buf
, S_IFBLK
| 0600, st
.st_dev
)) {
1312 fprintf(stderr
, "%s: cannot create device %s\n", program
, devname
);
1316 atexit(device_cleanup
); /* unlink the device node on exit */
1317 devname
= devname_buf
;
1322 devname
= find_device("/proc/mounts", st
.st_dev
);
1325 /* Didn't find it in /proc/mounts, try /etc/mtab */
1326 devname
= find_device("/etc/mtab", st
.st_dev
);
1329 devname
= find_device_sysfs(st
.st_dev
);
1331 fprintf(stderr
, "%s: cannot find device for path %s\n", program
, path
);
1335 fprintf(stderr
, "%s is device %s\n", path
, devname
);
1341 static int open_device(const char *path
, struct stat
*st
, const char **_devname
)
1344 const char *devname
= NULL
;
1348 if (stat(path
, st
) || !S_ISDIR(st
->st_mode
)) {
1349 fprintf(stderr
, "%s: Not a directory: %s\n", program
, path
);
1353 if (statfs(path
, &sfs
)) {
1354 fprintf(stderr
, "%s: statfs %s: %s\n", program
, path
, strerror(errno
));
1358 if (sfs
.f_type
== EXT2_SUPER_MAGIC
)
1360 else if (sfs
.f_type
== BTRFS_SUPER_MAGIC
)
1362 else if (sfs
.f_type
== MSDOS_SUPER_MAGIC
)
1364 else if (sfs
.f_type
== NTFS_SB_MAGIC
||
1365 sfs
.f_type
== FUSE_SUPER_MAGIC
/* ntfs-3g */)
1367 else if (sfs
.f_type
== XFS_SUPER_MAGIC
)
1369 else if (sfs
.f_type
== UFS1_SUPER_MAGIC
)
1371 else if (sfs
.f_type
== UFS2_SUPER_MAGIC
)
1376 "%s: not a fat, ntfs, ext2/3/4, btrfs, xfs or"
1377 "ufs1/2 filesystem: %s\n",
1383 devname
= get_devname(path
);
1385 *_devname
= devname
;
1387 if ((devfd
= open(devname
, O_RDWR
| O_SYNC
)) < 0) {
1388 fprintf(stderr
, "%s: cannot open device %s\n", program
, devname
);
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
);
1402 static int btrfs_read_adv(int devfd
)
1404 if (xpread(devfd
, syslinux_adv
, 2 * ADV_SIZE
, BTRFS_ADV_OFFSET
)
1408 return syslinux_validate_adv(syslinux_adv
) ? 1 : 0;
1411 static inline int xfs_read_adv(int devfd
)
1413 const size_t adv_size
= 2 * ADV_SIZE
;
1415 if (xpread(devfd
, syslinux_adv
, adv_size
, boot_image_len
) != adv_size
)
1418 return syslinux_validate_adv(syslinux_adv
) ? 1 : 0;
1421 static int ext_read_adv(const char *path
, int devfd
, const char **namep
)
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
);
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");
1442 static int ext_write_adv(const char *path
, const char *cfg
, int devfd
)
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");
1452 return write_adv(path
, cfg
);
1455 static int install_loader(const char *path
, int update_only
)
1457 struct stat st
, fst
;
1459 const char *devname
;
1461 devfd
= open_device(path
, &st
, &devname
);
1465 if (update_only
&& !syslinux_already_installed(devfd
)) {
1466 fprintf(stderr
, "%s: no previous syslinux boot sector found\n",
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) {
1480 if (modify_adv() < 0) {
1485 /* Install ldlinux.sys */
1486 if (install_file(path
, devfd
, &fst
)) {
1490 if (fst
.st_dev
!= st
.st_dev
) {
1491 fprintf(stderr
, "%s: file system changed under us - aborting!\n",
1498 rv
= install_bootblock(devfd
, devname
);
1506 * Modify the ADV of an existing installation
1508 int modify_existing_adv(const char *path
)
1510 const char *filename
;
1513 devfd
= open_device(path
, NULL
, NULL
);
1517 if (ext_read_adv(path
, devfd
, &filename
) < 0) {
1521 if (modify_adv() < 0) {
1525 if (ext_write_adv(path
, filename
, devfd
) < 0) {
1533 int main(int argc
, char *argv
[])
1535 parse_options(argc
, argv
, MODE_EXTLINUX
);
1537 if (!opt
.directory
|| opt
.install_mbr
|| opt
.activate_partition
)
1540 if (opt
.update_only
== -1) {
1541 if (opt
.reset_adv
|| opt
.set_once
|| opt
.menu_save
)
1542 return modify_existing_adv(opt
.directory
);
1544 usage(EX_USAGE
, MODE_EXTLINUX
);
1547 return install_loader(opt
.directory
, opt
.update_only
);