1 /* ----------------------------------------------------------------------- *
3 * Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
4 * Copyright 2009-2012 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 and xfs
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"
54 #include "../version.h"
56 #include "syslxcom.h" /* common functions shared with extlinux and syslinux */
59 #include "syslxopt.h" /* unified options */
60 #include "mountinfo.h"
63 # define dprintf printf
65 # define dprintf(...) ((void)0)
68 #ifndef EXT2_SUPER_OFFSET
69 #define EXT2_SUPER_OFFSET 1024
72 /* Since we have unused 2048 bytes in the primary AG of an XFS partition,
73 * we will use the first 0~512 bytes starting from 2048 for the Syslinux
76 #define XFS_BOOTSECT_OFFSET (4 << SECTOR_SHIFT)
77 #define XFS_SUPPORTED_BLOCKSIZE 4096 /* 4 KiB filesystem block size */
79 /* the btrfs partition first 64K blank area is used to store boot sector and
80 boot image, the boot sector is from 0~512, the boot image starts after */
81 #define BTRFS_BOOTSECT_AREA 65536
82 #define BTRFS_EXTLINUX_OFFSET SECTOR_SIZE
83 #define BTRFS_SUBVOL_MAX 256 /* By btrfs specification */
84 static char subvol
[BTRFS_SUBVOL_MAX
];
86 #define BTRFS_ADV_OFFSET (BTRFS_BOOTSECT_AREA - 2 * ADV_SIZE)
89 * Get the size of a block device
91 static uint64_t get_size(int devfd
)
98 if (!ioctl(devfd
, BLKGETSIZE64
, &bytes
))
101 if (!ioctl(devfd
, BLKGETSIZE
, §s
))
102 return (uint64_t) sects
<< 9;
103 else if (!fstat(devfd
, &st
) && st
.st_size
)
110 * Get device geometry and partition offset
112 struct geometry_table
{
114 struct hd_geometry g
;
117 static int sysfs_get_offset(int devfd
, unsigned long *start
)
120 char sysfs_name
[128];
124 if (fstat(devfd
, &st
))
127 if ((size_t)snprintf(sysfs_name
, sizeof sysfs_name
,
128 "/sys/dev/block/%u:%u/start",
129 major(st
.st_rdev
), minor(st
.st_rdev
))
130 >= sizeof sysfs_name
)
133 f
= fopen(sysfs_name
, "r");
137 rv
= fscanf(f
, "%lu", start
);
140 return (rv
== 1) ? 0 : -1;
143 /* Standard floppy disk geometries, plus LS-120. Zipdisk geometry
144 (x/64/32) is the final fallback. I don't know what LS-240 has
145 as its geometry, since I don't have one and don't know anyone that does,
146 and Google wasn't helpful... */
147 static const struct geometry_table standard_geometries
[] = {
148 {360 * 1024, {2, 9, 40, 0}},
149 {720 * 1024, {2, 9, 80, 0}},
150 {1200 * 1024, {2, 15, 80, 0}},
151 {1440 * 1024, {2, 18, 80, 0}},
152 {1680 * 1024, {2, 21, 80, 0}},
153 {1722 * 1024, {2, 21, 80, 0}},
154 {2880 * 1024, {2, 36, 80, 0}},
155 {3840 * 1024, {2, 48, 80, 0}},
156 {123264 * 1024, {8, 32, 963, 0}}, /* LS120 */
160 int get_geometry(int devfd
, uint64_t totalbytes
, struct hd_geometry
*geo
)
162 struct floppy_struct fd_str
;
164 struct loop_info64 li64
;
165 const struct geometry_table
*gp
;
168 memset(geo
, 0, sizeof *geo
);
170 if (!ioctl(devfd
, HDIO_GETGEO
, geo
)) {
172 } else if (!ioctl(devfd
, FDGETPRM
, &fd_str
)) {
173 geo
->heads
= fd_str
.head
;
174 geo
->sectors
= fd_str
.sect
;
175 geo
->cylinders
= fd_str
.track
;
180 /* Didn't work. Let's see if this is one of the standard geometries */
181 for (gp
= standard_geometries
; gp
->bytes
; gp
++) {
182 if (gp
->bytes
== totalbytes
) {
183 memcpy(geo
, &gp
->g
, sizeof *geo
);
188 /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is
189 what zipdisks use, so this would help if someone has a USB key that
190 they're booting in USB-ZIP mode. */
192 geo
->heads
= opt
.heads
? : 64;
193 geo
->sectors
= opt
.sectors
? : 32;
194 geo
->cylinders
= totalbytes
/ (geo
->heads
* geo
->sectors
<< SECTOR_SHIFT
);
197 if (!opt
.sectors
&& !opt
.heads
) {
199 "Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n"
200 " (on hard disks, this is usually harmless.)\n",
201 geo
->heads
, geo
->sectors
);
202 rv
= 1; /* Suboptimal result */
206 /* If this is a loopback device, try to set the start */
207 if (!ioctl(devfd
, LOOP_GET_STATUS64
, &li64
))
208 geo
->start
= li64
.lo_offset
>> SECTOR_SHIFT
;
209 else if (!ioctl(devfd
, LOOP_GET_STATUS
, &li
))
210 geo
->start
= (unsigned int)li
.lo_offset
>> SECTOR_SHIFT
;
211 else if (!sysfs_get_offset(devfd
, &geo
->start
)) {
219 * Query the device geometry and put it into the boot sector.
220 * Map the file and put the map in the boot sector and file.
221 * Stick the "current directory" inode number into the file.
223 * Returns the number of modified bytes in the boot file.
225 static int patch_file_and_bootblock(int fd
, const char *dir
, int devfd
)
227 struct stat dirst
, xdst
;
228 struct hd_geometry geo
;
230 uint64_t totalbytes
, totalsectors
;
232 struct fat_boot_sector
*sbs
;
233 char *dirpath
, *subpath
, *xdirpath
;
236 dirpath
= realpath(dir
, NULL
);
237 if (!dirpath
|| stat(dir
, &dirst
)) {
238 perror("accessing install directory");
239 exit(255); /* This should never happen */
242 if (lstat(dirpath
, &xdst
) ||
243 dirst
.st_ino
!= xdst
.st_ino
||
244 dirst
.st_dev
!= xdst
.st_dev
) {
245 perror("realpath returned nonsense");
249 subpath
= strchr(dirpath
, '\0');
251 if (*subpath
== '/') {
252 if (subpath
> dirpath
) {
258 if (lstat(xdirpath
, &xdst
) || dirst
.st_dev
!= xdst
.st_dev
) {
259 subpath
= strchr(subpath
+1, '/');
261 subpath
= "/"; /* It's the root of the filesystem */
267 if (subpath
== dirpath
)
273 /* Now subpath should contain the path relative to the fs base */
274 dprintf("subpath = %s\n", subpath
);
276 totalbytes
= get_size(devfd
);
277 get_geometry(devfd
, totalbytes
, &geo
);
280 geo
.heads
= opt
.heads
;
282 geo
.sectors
= opt
.sectors
;
284 /* Patch this into a fake FAT superblock. This isn't because
285 FAT is a good format in any way, it's because it lets the
286 early bootstrap share code with the FAT version. */
287 dprintf("heads = %u, sect = %u\n", geo
.heads
, geo
.sectors
);
289 sbs
= (struct fat_boot_sector
*)syslinux_bootsect
;
291 totalsectors
= totalbytes
>> SECTOR_SHIFT
;
292 if (totalsectors
>= 65536) {
293 set_16(&sbs
->bsSectors
, 0);
295 set_16(&sbs
->bsSectors
, totalsectors
);
297 set_32(&sbs
->bsHugeSectors
, totalsectors
);
299 set_16(&sbs
->bsBytesPerSec
, SECTOR_SIZE
);
300 set_16(&sbs
->bsSecPerTrack
, geo
.sectors
);
301 set_16(&sbs
->bsHeads
, geo
.heads
);
302 set_32(&sbs
->bsHiddenSecs
, geo
.start
);
304 /* Construct the boot file map */
306 dprintf("directory inode = %lu\n", (unsigned long)dirst
.st_ino
);
307 nsect
= (boot_image_len
+ SECTOR_SIZE
- 1) >> SECTOR_SHIFT
;
308 nsect
+= 2; /* Two sectors for the ADV */
309 sectp
= alloca(sizeof(sector_t
) * nsect
);
310 if (fs_type
== EXT2
|| fs_type
== VFAT
|| fs_type
== NTFS
||
312 if (sectmap(fd
, sectp
, nsect
)) {
316 } else if (fs_type
== BTRFS
) {
318 sector_t
*sp
= sectp
;
320 for (i
= 0; i
< nsect
- 2; i
++)
321 *sp
++ = BTRFS_EXTLINUX_OFFSET
/SECTOR_SIZE
+ i
;
322 for (i
= 0; i
< 2; i
++)
323 *sp
++ = BTRFS_ADV_OFFSET
/SECTOR_SIZE
+ i
;
326 /* Create the modified image in memory */
327 rv
= syslinux_patch(sectp
, nsect
, opt
.stupid_mode
,
328 opt
.raid_mode
, subpath
, subvol
);
335 * Install the boot block on the specified device.
336 * Must be run AFTER install_file()!
338 int install_bootblock(int fd
, const char *device
)
340 struct ext2_super_block sb
;
341 struct btrfs_super_block sb2
;
342 struct fat_boot_sector sb3
;
343 struct ntfs_boot_sector sb4
;
347 if (fs_type
== EXT2
) {
348 if (xpread(fd
, &sb
, sizeof sb
, EXT2_SUPER_OFFSET
) != sizeof sb
) {
349 perror("reading superblock");
353 if (sb
.s_magic
== EXT2_SUPER_MAGIC
)
355 } else if (fs_type
== BTRFS
) {
356 if (xpread(fd
, &sb2
, sizeof sb2
, BTRFS_SUPER_INFO_OFFSET
)
358 perror("reading superblock");
361 if (!memcmp(sb2
.magic
, BTRFS_MAGIC
, BTRFS_MAGIC_L
))
363 } else if (fs_type
== VFAT
) {
364 if (xpread(fd
, &sb3
, sizeof sb3
, 0) != sizeof sb3
) {
365 perror("reading fat superblock");
369 if (fat_check_sb_fields(&sb3
))
371 } else if (fs_type
== NTFS
) {
372 if (xpread(fd
, &sb4
, sizeof(sb4
), 0) != sizeof(sb4
)) {
373 perror("reading ntfs superblock");
377 if (ntfs_check_sb_fields(&sb4
))
379 } else if (fs_type
== XFS
) {
380 if (xpread(fd
, &sb5
, sizeof sb5
, 0) != sizeof sb5
) {
381 perror("reading xfs superblock");
385 if (sb5
.sb_magicnum
== *(u32
*)XFS_SB_MAGIC
) {
386 if (be32_to_cpu(sb5
.sb_blocksize
) != XFS_SUPPORTED_BLOCKSIZE
) {
388 "You need to have 4 KiB filesystem block size for "
389 " being able to install Syslinux in your XFS "
390 "partition (because there is no enough space in MBR to "
391 "determine where Syslinux bootsector can be installed "
392 "regardless the filesystem block size)\n");
402 "no fat, ntfs, ext2/3/4, btrfs or xfs superblock found on %s\n",
407 if (fs_type
== VFAT
) {
408 struct fat_boot_sector
*sbs
= (struct fat_boot_sector
*)syslinux_bootsect
;
409 if (xpwrite(fd
, &sbs
->FAT_bsHead
, FAT_bsHeadLen
, 0) != FAT_bsHeadLen
||
410 xpwrite(fd
, &sbs
->FAT_bsCode
, FAT_bsCodeLen
,
411 offsetof(struct fat_boot_sector
, FAT_bsCode
)) != FAT_bsCodeLen
) {
412 perror("writing fat bootblock");
415 } else if (fs_type
== NTFS
) {
416 struct ntfs_boot_sector
*sbs
=
417 (struct ntfs_boot_sector
*)syslinux_bootsect
;
418 if (xpwrite(fd
, &sbs
->NTFS_bsHead
,
419 NTFS_bsHeadLen
, 0) != NTFS_bsHeadLen
||
420 xpwrite(fd
, &sbs
->NTFS_bsCode
, NTFS_bsCodeLen
,
421 offsetof(struct ntfs_boot_sector
,
422 NTFS_bsCode
)) != NTFS_bsCodeLen
) {
423 perror("writing ntfs bootblock");
426 } else if (fs_type
== XFS
) {
427 if (xpwrite(fd
, syslinux_bootsect
, syslinux_bootsect_len
,
428 XFS_BOOTSECT_OFFSET
) != syslinux_bootsect_len
) {
429 perror("writing xfs bootblock");
433 if (xpwrite(fd
, syslinux_bootsect
, syslinux_bootsect_len
, 0)
434 != syslinux_bootsect_len
) {
435 perror("writing bootblock");
443 static int rewrite_boot_image(int devfd
, const char *path
, const char *filename
)
449 /* Let's create LDLINUX.SYS file again (if it already exists, of course) */
450 fd
= open(filename
, O_WRONLY
| O_TRUNC
| O_CREAT
| O_SYNC
,
451 S_IRUSR
| S_IRGRP
| S_IROTH
);
457 /* Write boot image data into LDLINUX.SYS file */
458 ret
= xpwrite(fd
, boot_image
, boot_image_len
, 0);
459 if (ret
!= boot_image_len
) {
460 perror("writing bootblock");
465 ret
= xpwrite(fd
, syslinux_adv
, 2 * ADV_SIZE
, boot_image_len
);
466 if (ret
!= 2 * ADV_SIZE
) {
467 fprintf(stderr
, "%s: write failure on %s\n", program
, filename
);
471 /* Map the file, and patch the initial sector accordingly */
472 modbytes
= patch_file_and_bootblock(fd
, path
, devfd
);
474 /* Write the patch area again - this relies on the file being overwritten
476 ret
= xpwrite(fd
, boot_image
, modbytes
, 0);
477 if (ret
!= modbytes
) {
478 fprintf(stderr
, "%s: write failure on %s\n", program
, filename
);
490 int ext2_fat_install_file(const char *path
, int devfd
, struct stat
*rst
)
492 char *file
, *oldfile
, *c32file
;
493 int fd
= -1, dirfd
= -1;
496 r1
= asprintf(&file
, "%s%sldlinux.sys",
497 path
, path
[0] && path
[strlen(path
) - 1] == '/' ? "" : "/");
498 r2
= asprintf(&oldfile
, "%s%sextlinux.sys",
499 path
, path
[0] && path
[strlen(path
) - 1] == '/' ? "" : "/");
500 r3
= asprintf(&c32file
, "%s%sldlinux.c32",
501 path
, path
[0] && path
[strlen(path
) - 1] == '/' ? "" : "/");
502 if (r1
< 0 || !file
|| r2
< 0 || !oldfile
|| r3
< 0 || !c32file
) {
507 dirfd
= open(path
, O_RDONLY
| O_DIRECTORY
);
513 fd
= open(file
, O_RDONLY
);
515 if (errno
!= ENOENT
) {
520 clear_attributes(fd
);
524 fd
= rewrite_boot_image(devfd
, path
, file
);
528 /* Attempt to set immutable flag and remove all write access */
529 /* Only set immutable flag if file is owned by root */
532 if (fstat(fd
, rst
)) {
540 /* Look if we have the old filename */
541 fd
= open(oldfile
, O_RDONLY
);
543 clear_attributes(fd
);
548 fd
= open(c32file
, O_WRONLY
| O_TRUNC
| O_CREAT
| O_SYNC
,
549 S_IRUSR
| S_IRGRP
| S_IROTH
);
555 r3
= xpwrite(fd
, syslinux_ldlinuxc32
, syslinux_ldlinuxc32_len
, 0);
556 if (r3
!= syslinux_ldlinuxc32_len
) {
557 fprintf(stderr
, "%s: write failure on %s\n", program
, c32file
);
578 /* btrfs has to install the ldlinux.sys in the first 64K blank area, which
579 is not managered by btrfs tree, so actually this is not installed as files.
580 since the cow feature of btrfs will move the ldlinux.sys every where */
581 int btrfs_install_file(const char *path
, int devfd
, struct stat
*rst
)
586 patch_file_and_bootblock(-1, path
, devfd
);
587 if (xpwrite(devfd
, boot_image
, boot_image_len
, BTRFS_EXTLINUX_OFFSET
)
589 perror("writing bootblock");
592 dprintf("write boot_image to 0x%x\n", BTRFS_EXTLINUX_OFFSET
);
593 if (xpwrite(devfd
, syslinux_adv
, 2 * ADV_SIZE
, BTRFS_ADV_OFFSET
)
595 perror("writing adv");
598 dprintf("write adv to 0x%x\n", BTRFS_ADV_OFFSET
);
599 if (stat(path
, rst
)) {
605 * Note that we *can* install ldinux.c32 as a regular file because
606 * it doesn't need to be within the first 64K. The Syslinux core
607 * has enough smarts to search the btrfs dirs and find this file.
609 rv
= asprintf(&file
, "%s%sldlinux.c32",
610 path
, path
[0] && path
[strlen(path
) - 1] == '/' ? "" : "/");
611 if (rv
< 0 || !file
) {
616 fd
= open(file
, O_WRONLY
| O_TRUNC
| O_CREAT
| O_SYNC
,
617 S_IRUSR
| S_IRGRP
| S_IROTH
);
624 rv
= xpwrite(fd
, syslinux_ldlinuxc32
, syslinux_ldlinuxc32_len
, 0);
625 if (rv
!= (int)syslinux_ldlinuxc32_len
) {
626 fprintf(stderr
, "%s: write failure on %s\n", program
, file
);
637 * Due to historical reasons (SGI IRIX's design of disk layouts), the first
638 * sector in the primary AG on XFS filesystems contains the superblock, which is
639 * a problem with bootloaders that rely on BIOSes (that load VBRs which are
640 * (located in the first sector of the partition).
642 * Thus, we need to handle this issue, otherwise Syslinux will damage the XFS's
645 static int xfs_install_file(const char *path
, int devfd
, struct stat
*rst
)
647 static char file
[PATH_MAX
+ 1];
648 static char c32file
[PATH_MAX
+ 1];
653 snprintf(file
, PATH_MAX
+ 1, "%s%sldlinux.sys", path
,
654 path
[0] && path
[strlen(path
) - 1] == '/' ? "" : "/");
655 snprintf(c32file
, PATH_MAX
+ 1, "%s%sldlinux.c32", path
,
656 path
[0] && path
[strlen(path
) - 1] == '/' ? "" : "/");
658 dirfd
= open(path
, O_RDONLY
| O_DIRECTORY
);
664 fd
= open(file
, O_RDONLY
);
666 if (errno
!= ENOENT
) {
671 clear_attributes(fd
);
676 fd
= rewrite_boot_image(devfd
, path
, file
);
680 /* Attempt to set immutable flag and remove all write access */
681 /* Only set immutable flag if file is owned by root */
684 if (fstat(fd
, rst
)) {
695 fd
= open(c32file
, O_WRONLY
| O_TRUNC
| O_CREAT
| O_SYNC
,
696 S_IRUSR
| S_IRGRP
| S_IROTH
);
702 retval
= xpwrite(fd
, syslinux_ldlinuxc32
, syslinux_ldlinuxc32_len
, 0);
703 if (retval
!= (int)syslinux_ldlinuxc32_len
) {
704 fprintf(stderr
, "%s: write failure on %s\n", program
, file
);
725 * * test if path is a subvolume:
726 * * this function return
727 * * 0-> path exists but it is not a subvolume
728 * * 1-> path exists and it is a subvolume
729 * * -1 -> path is unaccessible
731 static int test_issubvolume(char *path
)
737 res
= stat(path
, &st
);
741 return (st
.st_ino
== 256) && S_ISDIR(st
.st_mode
);
746 * Get the default subvolume of a btrfs filesystem
747 * rootdir: btrfs root dir
748 * subvol: this function will save the default subvolume name here
750 static char * get_default_subvol(char * rootdir
, char * subvol
)
752 struct btrfs_ioctl_search_args args
;
753 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
754 struct btrfs_ioctl_search_header
*sh
;
757 struct btrfs_root_ref
*ref
;
758 struct btrfs_dir_item
*dir_item
;
759 unsigned long off
= 0;
763 u64 defaultsubvolid
= 0;
765 ret
= test_issubvolume(rootdir
);
767 fd
= open(rootdir
, O_RDONLY
);
769 fprintf(stderr
, "ERROR: failed to open %s\n", rootdir
);
778 memset(&args
, 0, sizeof(args
));
780 /* search in the tree of tree roots */
784 * set the min and max to backref keys. The search will
785 * only send back this type of key now.
787 sk
->max_type
= BTRFS_DIR_ITEM_KEY
;
788 sk
->min_type
= BTRFS_DIR_ITEM_KEY
;
791 * set all the other params to the max, we'll take any objectid
794 sk
->min_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
795 sk
->max_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
797 sk
->max_offset
= (u64
)-1;
799 sk
->max_transid
= (u64
)-1;
801 /* just a big number, doesn't matter much */
805 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
807 fprintf(stderr
, "ERROR: can't perform the search\n");
811 /* the ioctl returns the number of item it found in nr_items */
812 if (sk
->nr_items
== 0) {
819 * for each item, pull the key out of the header and then
820 * read the root_ref item it contains
822 for (i
= 0; i
< sk
->nr_items
; i
++) {
823 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+ off
);
825 if (sh
->type
== BTRFS_DIR_ITEM_KEY
) {
826 dir_item
= (struct btrfs_dir_item
*)(args
.buf
+ off
);
827 name_len
= dir_item
->name_len
;
828 name
= (char *)(dir_item
+ 1);
831 /*add_root(&root_lookup, sh->objectid, sh->offset,
832 dir_id, name, name_len);*/
833 strncpy(dirname
, name
, name_len
);
834 dirname
[name_len
] = '\0';
835 if (strcmp(dirname
, "default") == 0) {
836 defaultsubvolid
= dir_item
->location
.objectid
;
843 * record the mins in sk so we can make sure the
844 * next search doesn't repeat this root
846 sk
->min_objectid
= sh
->objectid
;
847 sk
->min_type
= sh
->type
;
848 sk
->max_type
= sh
->type
;
849 sk
->min_offset
= sh
->offset
;
851 if (defaultsubvolid
!= 0)
854 /* this iteration is done, step forward one root for the next
857 if (sk
->min_objectid
< (u64
)-1) {
858 sk
->min_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
859 sk
->max_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
860 sk
->max_type
= BTRFS_ROOT_BACKREF_KEY
;
861 sk
->min_type
= BTRFS_ROOT_BACKREF_KEY
;
867 if (defaultsubvolid
== 0) {
872 memset(&args
, 0, sizeof(args
));
874 /* search in the tree of tree roots */
878 * set the min and max to backref keys. The search will
879 * only send back this type of key now.
881 sk
->max_type
= BTRFS_ROOT_BACKREF_KEY
;
882 sk
->min_type
= BTRFS_ROOT_BACKREF_KEY
;
885 * set all the other params to the max, we'll take any objectid
888 sk
->max_objectid
= (u64
)-1;
889 sk
->max_offset
= (u64
)-1;
890 sk
->max_transid
= (u64
)-1;
892 /* just a big number, doesn't matter much */
896 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
898 fprintf(stderr
, "ERROR: can't perform the search\n");
902 /* the ioctl returns the number of item it found in nr_items */
903 if (sk
->nr_items
== 0)
909 * for each item, pull the key out of the header and then
910 * read the root_ref item it contains
912 for (i
= 0; i
< sk
->nr_items
; i
++) {
913 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+ off
);
915 if (sh
->type
== BTRFS_ROOT_BACKREF_KEY
) {
916 ref
= (struct btrfs_root_ref
*)(args
.buf
+ off
);
917 name_len
= ref
->name_len
;
918 name
= (char *)(ref
+ 1);
920 if (sh
->objectid
== defaultsubvolid
) {
921 strncpy(subvol
, name
, name_len
);
922 subvol
[name_len
] = '\0';
923 dprintf("The default subvolume: %s, ID: %llu\n",
924 subvol
, sh
->objectid
);
933 * record the mins in sk so we can make sure the
934 * next search doesn't repeat this root
936 sk
->min_objectid
= sh
->objectid
;
937 sk
->min_type
= sh
->type
;
938 sk
->min_offset
= sh
->offset
;
940 if (subvol
[0] != '\0')
943 /* this iteration is done, step forward one root for the next
946 if (sk
->min_objectid
< (u64
)-1) {
948 sk
->min_type
= BTRFS_ROOT_BACKREF_KEY
;
956 static int install_file(const char *path
, int devfd
, struct stat
*rst
)
958 if (fs_type
== EXT2
|| fs_type
== VFAT
|| fs_type
== NTFS
)
959 return ext2_fat_install_file(path
, devfd
, rst
);
960 else if (fs_type
== BTRFS
)
961 return btrfs_install_file(path
, devfd
, rst
);
962 else if (fs_type
== XFS
)
963 return xfs_install_file(path
, devfd
, rst
);
969 static char devname_buf
[64];
971 static void device_cleanup(void)
977 /* Verify that a device fd and a pathname agree.
978 Return 0 on valid, -1 on error. */
979 static int validate_device_btrfs(int pathfd
, int devfd
);
980 static int validate_device(const char *path
, int devfd
)
982 struct stat pst
, dst
;
987 pfd
= open(path
, O_RDONLY
|O_DIRECTORY
);
991 if (fstat(pfd
, &pst
) || fstat(devfd
, &dst
) || statfs(path
, &sfs
))
994 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
995 if (fs_type
== BTRFS
) {
996 if (sfs
.f_type
== BTRFS_SUPER_MAGIC
)
997 rv
= validate_device_btrfs(pfd
, devfd
);
999 rv
= (pst
.st_dev
== dst
.st_rdev
) ? 0 : -1;
1009 static const char *find_device(const char *mtab_file
, dev_t dev
)
1014 const char *devname
= NULL
;
1017 mtab
= setmntent(mtab_file
, "r");
1022 while ((mnt
= getmntent(mtab
))) {
1023 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
1026 if (!strcmp(mnt
->mnt_type
, "btrfs") &&
1027 !stat(mnt
->mnt_dir
, &dst
) &&
1028 dst
.st_dev
== dev
) {
1030 get_default_subvol(mnt
->mnt_dir
, subvol
);
1035 if ((!strcmp(mnt
->mnt_type
, "ext2") ||
1036 !strcmp(mnt
->mnt_type
, "ext3") ||
1037 !strcmp(mnt
->mnt_type
, "ext4")) &&
1038 !stat(mnt
->mnt_fsname
, &dst
) &&
1039 dst
.st_rdev
== dev
) {
1044 if ((!strcmp(mnt
->mnt_type
, "vfat")) &&
1045 !stat(mnt
->mnt_fsname
, &dst
) &&
1046 dst
.st_rdev
== dev
) {
1051 if ((!strcmp(mnt
->mnt_type
, "fuseblk") /* ntfs-3g */ ||
1052 !strcmp(mnt
->mnt_type
, "ntfs")) &&
1053 !stat(mnt
->mnt_fsname
, &dst
) &&
1054 dst
.st_rdev
== dev
) {
1061 if (!strcmp(mnt
->mnt_type
, "xfs") && !stat(mnt
->mnt_fsname
, &dst
) &&
1062 dst
.st_rdev
== dev
) {
1071 devname
= strdup(mnt
->mnt_fsname
);
1083 * On newer Linux kernels we can use sysfs to get a backwards mapping
1084 * from device names to standard filenames
1086 static const char *find_device_sysfs(dev_t dev
)
1089 char linkname
[PATH_MAX
];
1095 snprintf(sysname
, sizeof sysname
, "/sys/dev/block/%u:%u",
1096 major(dev
), minor(dev
));
1098 llen
= readlink(sysname
, linkname
, sizeof linkname
);
1099 if (llen
< 0 || llen
>= sizeof linkname
)
1102 linkname
[llen
] = '\0';
1104 p
= strrchr(linkname
, '/');
1105 p
= p
? p
+1 : linkname
; /* Leave basename */
1107 buf
= q
= malloc(strlen(p
) + 6);
1111 memcpy(q
, "/dev/", 5);
1115 *q
++ = (*p
== '!') ? '/' : *p
;
1121 if (!stat(buf
, &st
) && st
.st_dev
== dev
)
1122 return buf
; /* Found it! */
1130 static const char *find_device_mountinfo(const char *path
, dev_t dev
)
1132 const struct mountinfo
*m
;
1135 m
= find_mount(path
, NULL
);
1139 if (m
->devpath
[0] == '/' && m
->dev
== dev
&&
1140 !stat(m
->devpath
, &st
) && S_ISBLK(st
.st_mode
) && st
.st_rdev
== dev
)
1146 static int validate_device_btrfs(int pfd
, int dfd
)
1148 struct btrfs_ioctl_fs_info_args fsinfo
;
1149 static struct btrfs_ioctl_dev_info_args devinfo
;
1150 struct btrfs_super_block sb2
;
1152 if (ioctl(pfd
, BTRFS_IOC_FS_INFO
, &fsinfo
))
1155 /* We do not support multi-device btrfs yet */
1156 if (fsinfo
.num_devices
!= 1)
1159 /* The one device will have the max devid */
1160 memset(&devinfo
, 0, sizeof devinfo
);
1161 devinfo
.devid
= fsinfo
.max_id
;
1162 if (ioctl(pfd
, BTRFS_IOC_DEV_INFO
, &devinfo
))
1165 if (devinfo
.path
[0] != '/')
1168 if (xpread(dfd
, &sb2
, sizeof sb2
, BTRFS_SUPER_INFO_OFFSET
) != sizeof sb2
)
1171 if (memcmp(sb2
.magic
, BTRFS_MAGIC
, BTRFS_MAGIC_L
))
1174 if (memcmp(sb2
.fsid
, fsinfo
.fsid
, sizeof fsinfo
.fsid
))
1177 if (sb2
.num_devices
!= 1)
1180 if (sb2
.dev_item
.devid
!= devinfo
.devid
)
1183 if (memcmp(sb2
.dev_item
.uuid
, devinfo
.uuid
, sizeof devinfo
.uuid
))
1186 if (memcmp(sb2
.dev_item
.fsid
, fsinfo
.fsid
, sizeof fsinfo
.fsid
))
1189 return 0; /* It's good! */
1192 static const char *find_device_btrfs(const char *path
)
1195 struct btrfs_ioctl_fs_info_args fsinfo
;
1196 static struct btrfs_ioctl_dev_info_args devinfo
;
1197 const char *rv
= NULL
;
1201 pfd
= open(path
, O_RDONLY
);
1205 if (ioctl(pfd
, BTRFS_IOC_FS_INFO
, &fsinfo
))
1208 /* We do not support multi-device btrfs yet */
1209 if (fsinfo
.num_devices
!= 1)
1212 /* The one device will have the max devid */
1213 memset(&devinfo
, 0, sizeof devinfo
);
1214 devinfo
.devid
= fsinfo
.max_id
;
1215 if (ioctl(pfd
, BTRFS_IOC_DEV_INFO
, &devinfo
))
1218 if (devinfo
.path
[0] != '/')
1221 dfd
= open((const char *)devinfo
.path
, O_RDONLY
);
1225 if (!validate_device_btrfs(pfd
, dfd
))
1226 rv
= (const char *)devinfo
.path
; /* It's good! */
1236 static const char *get_devname(const char *path
)
1238 const char *devname
= NULL
;
1242 if (stat(path
, &st
) || !S_ISDIR(st
.st_mode
)) {
1243 fprintf(stderr
, "%s: Not a directory: %s\n", program
, path
);
1246 if (statfs(path
, &sfs
)) {
1247 fprintf(stderr
, "%s: statfs %s: %s\n", program
, path
, strerror(errno
));
1252 devname
= opt
.device
;
1255 if (fs_type
== BTRFS
) {
1256 /* For btrfs try to get the device name from btrfs itself */
1257 devname
= find_device_btrfs(path
);
1262 devname
= find_device_mountinfo(path
, st
.st_dev
);
1267 devname
= find_device_sysfs(st
.st_dev
);
1270 /* klibc doesn't have getmntent and friends; instead, just create
1271 a new device with the appropriate device type */
1272 snprintf(devname_buf
, sizeof devname_buf
, "/tmp/dev-%u:%u",
1273 major(st
.st_dev
), minor(st
.st_dev
));
1275 if (mknod(devname_buf
, S_IFBLK
| 0600, st
.st_dev
)) {
1276 fprintf(stderr
, "%s: cannot create device %s\n", program
, devname
);
1280 atexit(device_cleanup
); /* unlink the device node on exit */
1281 devname
= devname_buf
;
1286 devname
= find_device("/proc/mounts", st
.st_dev
);
1289 /* Didn't find it in /proc/mounts, try /etc/mtab */
1290 devname
= find_device("/etc/mtab", st
.st_dev
);
1293 devname
= find_device_sysfs(st
.st_dev
);
1295 fprintf(stderr
, "%s: cannot find device for path %s\n", program
, path
);
1299 fprintf(stderr
, "%s is device %s\n", path
, devname
);
1305 static int open_device(const char *path
, struct stat
*st
, const char **_devname
)
1308 const char *devname
= NULL
;
1312 if (stat(path
, st
) || !S_ISDIR(st
->st_mode
)) {
1313 fprintf(stderr
, "%s: Not a directory: %s\n", program
, path
);
1317 if (statfs(path
, &sfs
)) {
1318 fprintf(stderr
, "%s: statfs %s: %s\n", program
, path
, strerror(errno
));
1322 if (sfs
.f_type
== EXT2_SUPER_MAGIC
)
1324 else if (sfs
.f_type
== BTRFS_SUPER_MAGIC
)
1326 else if (sfs
.f_type
== MSDOS_SUPER_MAGIC
)
1328 else if (sfs
.f_type
== NTFS_SB_MAGIC
||
1329 sfs
.f_type
== FUSE_SUPER_MAGIC
/* ntfs-3g */)
1331 else if (sfs
.f_type
== XFS_SUPER_MAGIC
)
1336 "%s: not a fat, ntfs, ext2/3/4, btrfs or xfs filesystem: %s\n",
1342 devname
= get_devname(path
);
1344 *_devname
= devname
;
1346 if ((devfd
= open(devname
, O_RDWR
| O_SYNC
)) < 0) {
1347 fprintf(stderr
, "%s: cannot open device %s\n", program
, devname
);
1351 /* Verify that the device we opened is the device intended */
1352 if (validate_device(path
, devfd
)) {
1353 fprintf(stderr
, "%s: path %s doesn't match device %s\n",
1354 program
, path
, devname
);
1361 static int btrfs_read_adv(int devfd
)
1363 if (xpread(devfd
, syslinux_adv
, 2 * ADV_SIZE
, BTRFS_ADV_OFFSET
)
1367 return syslinux_validate_adv(syslinux_adv
) ? 1 : 0;
1370 static inline int xfs_read_adv(int devfd
)
1372 const size_t adv_size
= 2 * ADV_SIZE
;
1374 if (xpread(devfd
, syslinux_adv
, adv_size
, boot_image_len
) != adv_size
)
1377 return syslinux_validate_adv(syslinux_adv
) ? 1 : 0;
1380 static int ext_read_adv(const char *path
, int devfd
, const char **namep
)
1385 if (fs_type
== BTRFS
) {
1386 /* btrfs "ldlinux.sys" is in 64k blank area */
1387 return btrfs_read_adv(devfd
);
1388 } else if (fs_type
== XFS
) {
1389 /* XFS "ldlinux.sys" is in the first 2048 bytes of the primary AG */
1390 return xfs_read_adv(devfd
);
1392 err
= read_adv(path
, name
= "ldlinux.sys");
1393 if (err
== 2) /* ldlinux.sys does not exist */
1394 err
= read_adv(path
, name
= "extlinux.sys");
1401 static int ext_write_adv(const char *path
, const char *cfg
, int devfd
)
1403 if (fs_type
== BTRFS
) { /* btrfs "ldlinux.sys" is in 64k blank area */
1404 if (xpwrite(devfd
, syslinux_adv
, 2 * ADV_SIZE
,
1405 BTRFS_ADV_OFFSET
) != 2 * ADV_SIZE
) {
1406 perror("writing adv");
1411 return write_adv(path
, cfg
);
1414 static int install_loader(const char *path
, int update_only
)
1416 struct stat st
, fst
;
1418 const char *devname
;
1420 devfd
= open_device(path
, &st
, &devname
);
1424 if (update_only
&& !syslinux_already_installed(devfd
)) {
1425 fprintf(stderr
, "%s: no previous syslinux boot sector found\n",
1431 /* Read a pre-existing ADV, if already installed */
1432 if (opt
.reset_adv
) {
1433 syslinux_reset_adv(syslinux_adv
);
1434 } else if (ext_read_adv(path
, devfd
, NULL
) < 0) {
1439 if (modify_adv() < 0) {
1444 /* Install ldlinux.sys */
1445 if (install_file(path
, devfd
, &fst
)) {
1449 if (fst
.st_dev
!= st
.st_dev
) {
1450 fprintf(stderr
, "%s: file system changed under us - aborting!\n",
1457 rv
= install_bootblock(devfd
, devname
);
1465 * Modify the ADV of an existing installation
1467 int modify_existing_adv(const char *path
)
1469 const char *filename
;
1472 devfd
= open_device(path
, NULL
, NULL
);
1476 if (ext_read_adv(path
, devfd
, &filename
) < 0) {
1480 if (modify_adv() < 0) {
1484 if (ext_write_adv(path
, filename
, devfd
) < 0) {
1492 int main(int argc
, char *argv
[])
1494 parse_options(argc
, argv
, MODE_EXTLINUX
);
1496 if (!opt
.directory
|| opt
.install_mbr
|| opt
.activate_partition
)
1499 if (opt
.update_only
== -1) {
1500 if (opt
.reset_adv
|| opt
.set_once
|| opt
.menu_save
)
1501 return modify_existing_adv(opt
.directory
);
1503 usage(EX_USAGE
, MODE_EXTLINUX
);
1506 return install_loader(opt
.directory
, opt
.update_only
);