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 and btrfs filesystem
20 #define _GNU_SOURCE /* Enable everything */
22 /* This is needed to deal with the kernel headers imported into glibc 3.3.3. */
38 #include <sys/ioctl.h>
40 #include <sys/types.h>
41 #include <sys/mount.h>
44 #include "linuxioctl.h"
49 #include "../version.h"
51 #include "syslxcom.h" /* common functions shared with extlinux and syslinux */
54 #include "syslxopt.h" /* unified options */
55 #include "mountinfo.h"
58 # define dprintf printf
60 # define dprintf(...) ((void)0)
63 #ifndef EXT2_SUPER_OFFSET
64 #define EXT2_SUPER_OFFSET 1024
67 /* the btrfs partition first 64K blank area is used to store boot sector and
68 boot image, the boot sector is from 0~512, the boot image starts after */
69 #define BTRFS_BOOTSECT_AREA 65536
70 #define BTRFS_EXTLINUX_OFFSET SECTOR_SIZE
71 #define BTRFS_SUBVOL_MAX 256 /* By btrfs specification */
72 static char subvol
[BTRFS_SUBVOL_MAX
];
74 #define BTRFS_ADV_OFFSET (BTRFS_BOOTSECT_AREA - 2 * ADV_SIZE)
77 * Get the size of a block device
79 uint64_t get_size(int devfd
)
86 if (!ioctl(devfd
, BLKGETSIZE64
, &bytes
))
89 if (!ioctl(devfd
, BLKGETSIZE
, §s
))
90 return (uint64_t) sects
<< 9;
91 else if (!fstat(devfd
, &st
) && st
.st_size
)
98 * Get device geometry and partition offset
100 struct geometry_table
{
102 struct hd_geometry g
;
105 static int sysfs_get_offset(int devfd
, unsigned long *start
)
108 char sysfs_name
[128];
112 if (fstat(devfd
, &st
))
115 if ((size_t)snprintf(sysfs_name
, sizeof sysfs_name
,
116 "/sys/dev/block/%u:%u/start",
117 major(st
.st_rdev
), minor(st
.st_rdev
))
118 >= sizeof sysfs_name
)
121 f
= fopen(sysfs_name
, "r");
125 rv
= fscanf(f
, "%lu", start
);
128 return (rv
== 1) ? 0 : -1;
131 /* Standard floppy disk geometries, plus LS-120. Zipdisk geometry
132 (x/64/32) is the final fallback. I don't know what LS-240 has
133 as its geometry, since I don't have one and don't know anyone that does,
134 and Google wasn't helpful... */
135 static const struct geometry_table standard_geometries
[] = {
136 {360 * 1024, {2, 9, 40, 0}},
137 {720 * 1024, {2, 9, 80, 0}},
138 {1200 * 1024, {2, 15, 80, 0}},
139 {1440 * 1024, {2, 18, 80, 0}},
140 {1680 * 1024, {2, 21, 80, 0}},
141 {1722 * 1024, {2, 21, 80, 0}},
142 {2880 * 1024, {2, 36, 80, 0}},
143 {3840 * 1024, {2, 48, 80, 0}},
144 {123264 * 1024, {8, 32, 963, 0}}, /* LS120 */
148 int get_geometry(int devfd
, uint64_t totalbytes
, struct hd_geometry
*geo
)
150 struct floppy_struct fd_str
;
152 struct loop_info64 li64
;
153 const struct geometry_table
*gp
;
156 memset(geo
, 0, sizeof *geo
);
158 if (!ioctl(devfd
, HDIO_GETGEO
, geo
)) {
160 } else if (!ioctl(devfd
, FDGETPRM
, &fd_str
)) {
161 geo
->heads
= fd_str
.head
;
162 geo
->sectors
= fd_str
.sect
;
163 geo
->cylinders
= fd_str
.track
;
168 /* Didn't work. Let's see if this is one of the standard geometries */
169 for (gp
= standard_geometries
; gp
->bytes
; gp
++) {
170 if (gp
->bytes
== totalbytes
) {
171 memcpy(geo
, &gp
->g
, sizeof *geo
);
176 /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is
177 what zipdisks use, so this would help if someone has a USB key that
178 they're booting in USB-ZIP mode. */
180 geo
->heads
= opt
.heads
? : 64;
181 geo
->sectors
= opt
.sectors
? : 32;
182 geo
->cylinders
= totalbytes
/ (geo
->heads
* geo
->sectors
<< SECTOR_SHIFT
);
185 if (!opt
.sectors
&& !opt
.heads
) {
187 "Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n"
188 " (on hard disks, this is usually harmless.)\n",
189 geo
->heads
, geo
->sectors
);
190 rv
= 1; /* Suboptimal result */
194 /* If this is a loopback device, try to set the start */
195 if (!ioctl(devfd
, LOOP_GET_STATUS64
, &li64
))
196 geo
->start
= li64
.lo_offset
>> SECTOR_SHIFT
;
197 else if (!ioctl(devfd
, LOOP_GET_STATUS
, &li
))
198 geo
->start
= (unsigned int)li
.lo_offset
>> SECTOR_SHIFT
;
199 else if (!sysfs_get_offset(devfd
, &geo
->start
)) {
207 * Query the device geometry and put it into the boot sector.
208 * Map the file and put the map in the boot sector and file.
209 * Stick the "current directory" inode number into the file.
211 * Returns the number of modified bytes in the boot file.
213 int patch_file_and_bootblock(int fd
, const char *dir
, int devfd
)
215 struct stat dirst
, xdst
;
216 struct hd_geometry geo
;
218 uint64_t totalbytes
, totalsectors
;
220 struct fat_boot_sector
*sbs
;
221 char *dirpath
, *subpath
, *xdirpath
;
224 dirpath
= realpath(dir
, NULL
);
225 if (!dirpath
|| stat(dir
, &dirst
)) {
226 perror("accessing install directory");
227 exit(255); /* This should never happen */
230 if (lstat(dirpath
, &xdst
) ||
231 dirst
.st_ino
!= xdst
.st_ino
||
232 dirst
.st_dev
!= xdst
.st_dev
) {
233 perror("realpath returned nonsense");
237 subpath
= strchr(dirpath
, '\0');
239 if (*subpath
== '/') {
240 if (subpath
> dirpath
) {
246 if (lstat(xdirpath
, &xdst
) || dirst
.st_dev
!= xdst
.st_dev
) {
247 subpath
= strchr(subpath
+1, '/');
249 subpath
= "/"; /* It's the root of the filesystem */
255 if (subpath
== dirpath
)
261 /* Now subpath should contain the path relative to the fs base */
262 dprintf("subpath = %s\n", subpath
);
264 totalbytes
= get_size(devfd
);
265 get_geometry(devfd
, totalbytes
, &geo
);
268 geo
.heads
= opt
.heads
;
270 geo
.sectors
= opt
.sectors
;
272 /* Patch this into a fake FAT superblock. This isn't because
273 FAT is a good format in any way, it's because it lets the
274 early bootstrap share code with the FAT version. */
275 dprintf("heads = %u, sect = %u\n", geo
.heads
, geo
.sectors
);
277 sbs
= (struct fat_boot_sector
*)syslinux_bootsect
;
279 totalsectors
= totalbytes
>> SECTOR_SHIFT
;
280 if (totalsectors
>= 65536) {
281 set_16(&sbs
->bsSectors
, 0);
283 set_16(&sbs
->bsSectors
, totalsectors
);
285 set_32(&sbs
->bsHugeSectors
, totalsectors
);
287 set_16(&sbs
->bsBytesPerSec
, SECTOR_SIZE
);
288 set_16(&sbs
->bsSecPerTrack
, geo
.sectors
);
289 set_16(&sbs
->bsHeads
, geo
.heads
);
290 set_32(&sbs
->bsHiddenSecs
, geo
.start
);
292 /* Construct the boot file map */
294 dprintf("directory inode = %lu\n", (unsigned long)dirst
.st_ino
);
295 nsect
= (boot_image_len
+ SECTOR_SIZE
- 1) >> SECTOR_SHIFT
;
296 nsect
+= 2; /* Two sectors for the ADV */
297 sectp
= alloca(sizeof(sector_t
) * nsect
);
298 if (fs_type
== EXT2
|| fs_type
== VFAT
|| fs_type
== NTFS
) {
299 if (sectmap(fd
, sectp
, nsect
)) {
303 } else if (fs_type
== BTRFS
) {
305 sector_t
*sp
= sectp
;
307 for (i
= 0; i
< nsect
- 2; i
++)
308 *sp
++ = BTRFS_EXTLINUX_OFFSET
/SECTOR_SIZE
+ i
;
309 for (i
= 0; i
< 2; i
++)
310 *sp
++ = BTRFS_ADV_OFFSET
/SECTOR_SIZE
+ i
;
313 /* Create the modified image in memory */
314 rv
= syslinux_patch(sectp
, nsect
, opt
.stupid_mode
,
315 opt
.raid_mode
, subpath
, subvol
);
322 * Install the boot block on the specified device.
323 * Must be run AFTER install_file()!
325 int install_bootblock(int fd
, const char *device
)
327 struct ext2_super_block sb
;
328 struct btrfs_super_block sb2
;
329 struct fat_boot_sector sb3
;
330 struct ntfs_boot_sector sb4
;
333 if (fs_type
== EXT2
) {
334 if (xpread(fd
, &sb
, sizeof sb
, EXT2_SUPER_OFFSET
) != sizeof sb
) {
335 perror("reading superblock");
338 if (sb
.s_magic
== EXT2_SUPER_MAGIC
)
340 } else if (fs_type
== BTRFS
) {
341 if (xpread(fd
, &sb2
, sizeof sb2
, BTRFS_SUPER_INFO_OFFSET
)
343 perror("reading superblock");
346 if (!memcmp(sb2
.magic
, BTRFS_MAGIC
, BTRFS_MAGIC_L
))
348 } else if (fs_type
== VFAT
) {
349 if (xpread(fd
, &sb3
, sizeof sb3
, 0) != sizeof sb3
) {
350 perror("reading fat superblock");
353 if (fat_check_sb_fields(&sb3
))
355 } else if (fs_type
== NTFS
) {
356 if (xpread(fd
, &sb4
, sizeof(sb4
), 0) != sizeof(sb4
)) {
357 perror("reading ntfs superblock");
361 if (ntfs_check_sb_fields(&sb4
))
365 fprintf(stderr
, "no fat, ntfs, ext2/3/4 or btrfs superblock found on %s\n",
369 if (fs_type
== VFAT
) {
370 struct fat_boot_sector
*sbs
= (struct fat_boot_sector
*)syslinux_bootsect
;
371 if (xpwrite(fd
, &sbs
->FAT_bsHead
, FAT_bsHeadLen
, 0) != FAT_bsHeadLen
||
372 xpwrite(fd
, &sbs
->FAT_bsCode
, FAT_bsCodeLen
,
373 offsetof(struct fat_boot_sector
, FAT_bsCode
)) != FAT_bsCodeLen
) {
374 perror("writing fat bootblock");
377 } else if (fs_type
== NTFS
) {
378 struct ntfs_boot_sector
*sbs
=
379 (struct ntfs_boot_sector
*)syslinux_bootsect
;
380 if (xpwrite(fd
, &sbs
->NTFS_bsHead
,
381 NTFS_bsHeadLen
, 0) != NTFS_bsHeadLen
||
382 xpwrite(fd
, &sbs
->NTFS_bsCode
, NTFS_bsCodeLen
,
383 offsetof(struct ntfs_boot_sector
,
384 NTFS_bsCode
)) != NTFS_bsCodeLen
) {
385 perror("writing ntfs bootblock");
389 if (xpwrite(fd
, syslinux_bootsect
, syslinux_bootsect_len
, 0)
390 != syslinux_bootsect_len
) {
391 perror("writing bootblock");
399 int ext2_fat_install_file(const char *path
, int devfd
, struct stat
*rst
)
401 char *file
, *oldfile
;
402 int fd
= -1, dirfd
= -1;
406 r1
= asprintf(&file
, "%s%sldlinux.sys",
407 path
, path
[0] && path
[strlen(path
) - 1] == '/' ? "" : "/");
408 r2
= asprintf(&oldfile
, "%s%sextlinux.sys",
409 path
, path
[0] && path
[strlen(path
) - 1] == '/' ? "" : "/");
410 if (r1
< 0 || !file
|| r2
< 0 || !oldfile
) {
415 dirfd
= open(path
, O_RDONLY
| O_DIRECTORY
);
421 fd
= open(file
, O_RDONLY
);
423 if (errno
!= ENOENT
) {
428 clear_attributes(fd
);
432 fd
= open(file
, O_WRONLY
| O_TRUNC
| O_CREAT
| O_SYNC
,
433 S_IRUSR
| S_IRGRP
| S_IROTH
);
439 /* Write it the first time */
440 if (xpwrite(fd
, boot_image
, boot_image_len
, 0) != boot_image_len
||
441 xpwrite(fd
, syslinux_adv
, 2 * ADV_SIZE
,
442 boot_image_len
) != 2 * ADV_SIZE
) {
443 fprintf(stderr
, "%s: write failure on %s\n", program
, file
);
447 /* Map the file, and patch the initial sector accordingly */
448 modbytes
= patch_file_and_bootblock(fd
, path
, devfd
);
450 /* Write the patch area again - this relies on the file being
451 overwritten in place! */
452 if (xpwrite(fd
, boot_image
, modbytes
, 0) != modbytes
) {
453 fprintf(stderr
, "%s: write failure on %s\n", program
, file
);
457 /* Attempt to set immutable flag and remove all write access */
458 /* Only set immutable flag if file is owned by root */
461 if (fstat(fd
, rst
)) {
469 /* Look if we have the old filename */
470 fd
= open(oldfile
, O_RDONLY
);
472 clear_attributes(fd
);
492 /* btrfs has to install the ldlinux.sys in the first 64K blank area, which
493 is not managered by btrfs tree, so actually this is not installed as files.
494 since the cow feature of btrfs will move the ldlinux.sys every where */
495 int btrfs_install_file(const char *path
, int devfd
, struct stat
*rst
)
497 patch_file_and_bootblock(-1, path
, devfd
);
498 if (xpwrite(devfd
, boot_image
, boot_image_len
, BTRFS_EXTLINUX_OFFSET
)
500 perror("writing bootblock");
503 dprintf("write boot_image to 0x%x\n", BTRFS_EXTLINUX_OFFSET
);
504 if (xpwrite(devfd
, syslinux_adv
, 2 * ADV_SIZE
, BTRFS_ADV_OFFSET
)
506 perror("writing adv");
509 dprintf("write adv to 0x%x\n", BTRFS_ADV_OFFSET
);
510 if (stat(path
, rst
)) {
518 * * test if path is a subvolume:
519 * * this function return
520 * * 0-> path exists but it is not a subvolume
521 * * 1-> path exists and it is a subvolume
522 * * -1 -> path is unaccessible
524 static int test_issubvolume(char *path
)
530 res
= stat(path
, &st
);
534 return (st
.st_ino
== 256) && S_ISDIR(st
.st_mode
);
539 * Get the default subvolume of a btrfs filesystem
540 * rootdir: btrfs root dir
541 * subvol: this function will save the default subvolume name here
543 static char * get_default_subvol(char * rootdir
, char * subvol
)
545 struct btrfs_ioctl_search_args args
;
546 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
547 struct btrfs_ioctl_search_header
*sh
;
550 struct btrfs_root_ref
*ref
;
551 struct btrfs_dir_item
*dir_item
;
552 unsigned long off
= 0;
556 u64 defaultsubvolid
= 0;
558 ret
= test_issubvolume(rootdir
);
560 fd
= open(rootdir
, O_RDONLY
);
562 fprintf(stderr
, "ERROR: failed to open %s\n", rootdir
);
571 memset(&args
, 0, sizeof(args
));
573 /* search in the tree of tree roots */
577 * set the min and max to backref keys. The search will
578 * only send back this type of key now.
580 sk
->max_type
= BTRFS_DIR_ITEM_KEY
;
581 sk
->min_type
= BTRFS_DIR_ITEM_KEY
;
584 * set all the other params to the max, we'll take any objectid
587 sk
->min_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
588 sk
->max_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
590 sk
->max_offset
= (u64
)-1;
592 sk
->max_transid
= (u64
)-1;
594 /* just a big number, doesn't matter much */
598 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
600 fprintf(stderr
, "ERROR: can't perform the search\n");
604 /* the ioctl returns the number of item it found in nr_items */
605 if (sk
->nr_items
== 0) {
612 * for each item, pull the key out of the header and then
613 * read the root_ref item it contains
615 for (i
= 0; i
< sk
->nr_items
; i
++) {
616 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+ off
);
618 if (sh
->type
== BTRFS_DIR_ITEM_KEY
) {
619 dir_item
= (struct btrfs_dir_item
*)(args
.buf
+ off
);
620 name_len
= dir_item
->name_len
;
621 name
= (char *)(dir_item
+ 1);
624 /*add_root(&root_lookup, sh->objectid, sh->offset,
625 dir_id, name, name_len);*/
626 strncpy(dirname
, name
, name_len
);
627 dirname
[name_len
] = '\0';
628 if (strcmp(dirname
, "default") == 0) {
629 defaultsubvolid
= dir_item
->location
.objectid
;
636 * record the mins in sk so we can make sure the
637 * next search doesn't repeat this root
639 sk
->min_objectid
= sh
->objectid
;
640 sk
->min_type
= sh
->type
;
641 sk
->max_type
= sh
->type
;
642 sk
->min_offset
= sh
->offset
;
644 if (defaultsubvolid
!= 0)
647 /* this iteration is done, step forward one root for the next
650 if (sk
->min_objectid
< (u64
)-1) {
651 sk
->min_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
652 sk
->max_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
653 sk
->max_type
= BTRFS_ROOT_BACKREF_KEY
;
654 sk
->min_type
= BTRFS_ROOT_BACKREF_KEY
;
660 if (defaultsubvolid
== 0) {
665 memset(&args
, 0, sizeof(args
));
667 /* search in the tree of tree roots */
671 * set the min and max to backref keys. The search will
672 * only send back this type of key now.
674 sk
->max_type
= BTRFS_ROOT_BACKREF_KEY
;
675 sk
->min_type
= BTRFS_ROOT_BACKREF_KEY
;
678 * set all the other params to the max, we'll take any objectid
681 sk
->max_objectid
= (u64
)-1;
682 sk
->max_offset
= (u64
)-1;
683 sk
->max_transid
= (u64
)-1;
685 /* just a big number, doesn't matter much */
689 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
691 fprintf(stderr
, "ERROR: can't perform the search\n");
695 /* the ioctl returns the number of item it found in nr_items */
696 if (sk
->nr_items
== 0)
702 * for each item, pull the key out of the header and then
703 * read the root_ref item it contains
705 for (i
= 0; i
< sk
->nr_items
; i
++) {
706 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+ off
);
708 if (sh
->type
== BTRFS_ROOT_BACKREF_KEY
) {
709 ref
= (struct btrfs_root_ref
*)(args
.buf
+ off
);
710 name_len
= ref
->name_len
;
711 name
= (char *)(ref
+ 1);
713 if (sh
->objectid
== defaultsubvolid
) {
714 strncpy(subvol
, name
, name_len
);
715 subvol
[name_len
] = '\0';
716 dprintf("The default subvolume: %s, ID: %llu\n",
717 subvol
, sh
->objectid
);
726 * record the mins in sk so we can make sure the
727 * next search doesn't repeat this root
729 sk
->min_objectid
= sh
->objectid
;
730 sk
->min_type
= sh
->type
;
731 sk
->min_offset
= sh
->offset
;
733 if (subvol
[0] != '\0')
736 /* this iteration is done, step forward one root for the next
739 if (sk
->min_objectid
< (u64
)-1) {
741 sk
->min_type
= BTRFS_ROOT_BACKREF_KEY
;
749 int install_file(const char *path
, int devfd
, struct stat
*rst
)
751 if (fs_type
== EXT2
|| fs_type
== VFAT
|| fs_type
== NTFS
)
752 return ext2_fat_install_file(path
, devfd
, rst
);
753 else if (fs_type
== BTRFS
)
754 return btrfs_install_file(path
, devfd
, rst
);
759 static char devname_buf
[64];
761 static void device_cleanup(void)
767 /* Verify that a device fd and a pathname agree.
768 Return 0 on valid, -1 on error. */
769 static int validate_device_btrfs(int pathfd
, int devfd
);
770 static int validate_device(const char *path
, int devfd
)
772 struct stat pst
, dst
;
777 pfd
= open(path
, O_RDONLY
|O_DIRECTORY
);
781 if (fstat(pfd
, &pst
) || fstat(devfd
, &dst
) || statfs(path
, &sfs
))
784 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
785 if (fs_type
== BTRFS
) {
786 if (sfs
.f_type
== BTRFS_SUPER_MAGIC
)
787 rv
= validate_device_btrfs(pfd
, devfd
);
789 rv
= (pst
.st_dev
== dst
.st_rdev
) ? 0 : -1;
799 static const char *find_device(const char *mtab_file
, dev_t dev
)
804 const char *devname
= NULL
;
807 mtab
= setmntent(mtab_file
, "r");
812 while ((mnt
= getmntent(mtab
))) {
813 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
816 if (!strcmp(mnt
->mnt_type
, "btrfs") &&
817 !stat(mnt
->mnt_dir
, &dst
) &&
820 get_default_subvol(mnt
->mnt_dir
, subvol
);
825 if ((!strcmp(mnt
->mnt_type
, "ext2") ||
826 !strcmp(mnt
->mnt_type
, "ext3") ||
827 !strcmp(mnt
->mnt_type
, "ext4")) &&
828 !stat(mnt
->mnt_fsname
, &dst
) &&
829 dst
.st_rdev
== dev
) {
834 if ((!strcmp(mnt
->mnt_type
, "vfat")) &&
835 !stat(mnt
->mnt_fsname
, &dst
) &&
836 dst
.st_rdev
== dev
) {
841 if ((!strcmp(mnt
->mnt_type
, "fuseblk") /* ntfs-3g */ ||
842 !strcmp(mnt
->mnt_type
, "ntfs")) &&
843 !stat(mnt
->mnt_fsname
, &dst
) &&
844 dst
.st_rdev
== dev
) {
854 devname
= strdup(mnt
->mnt_fsname
);
865 * On newer Linux kernels we can use sysfs to get a backwards mapping
866 * from device names to standard filenames
868 static const char *find_device_sysfs(dev_t dev
)
871 char linkname
[PATH_MAX
];
877 snprintf(sysname
, sizeof sysname
, "/sys/dev/block/%u:%u",
878 major(dev
), minor(dev
));
880 llen
= readlink(sysname
, linkname
, sizeof linkname
);
881 if (llen
< 0 || llen
>= sizeof linkname
)
884 linkname
[llen
] = '\0';
886 p
= strrchr(linkname
, '/');
887 p
= p
? p
+1 : linkname
; /* Leave basename */
889 buf
= q
= malloc(strlen(p
) + 6);
893 memcpy(q
, "/dev/", 5);
897 *q
++ = (*p
== '!') ? '/' : *p
;
903 if (!stat(buf
, &st
) && st
.st_dev
== dev
)
904 return buf
; /* Found it! */
912 static const char *find_device_mountinfo(const char *path
, dev_t dev
)
914 const struct mountinfo
*m
;
917 m
= find_mount(path
, NULL
);
919 if (m
->devpath
[0] == '/' && m
->dev
== dev
&&
920 !stat(m
->devpath
, &st
) && S_ISBLK(st
.st_mode
) && st
.st_rdev
== dev
)
926 static int validate_device_btrfs(int pfd
, int dfd
)
928 struct btrfs_ioctl_fs_info_args fsinfo
;
929 static struct btrfs_ioctl_dev_info_args devinfo
;
930 struct btrfs_super_block sb2
;
932 if (ioctl(pfd
, BTRFS_IOC_FS_INFO
, &fsinfo
))
935 /* We do not support multi-device btrfs yet */
936 if (fsinfo
.num_devices
!= 1)
939 /* The one device will have the max devid */
940 memset(&devinfo
, 0, sizeof devinfo
);
941 devinfo
.devid
= fsinfo
.max_id
;
942 if (ioctl(pfd
, BTRFS_IOC_DEV_INFO
, &devinfo
))
945 if (devinfo
.path
[0] != '/')
948 if (xpread(dfd
, &sb2
, sizeof sb2
, BTRFS_SUPER_INFO_OFFSET
) != sizeof sb2
)
951 if (memcmp(sb2
.magic
, BTRFS_MAGIC
, BTRFS_MAGIC_L
))
954 if (memcmp(sb2
.fsid
, fsinfo
.fsid
, sizeof fsinfo
.fsid
))
957 if (sb2
.num_devices
!= 1)
960 if (sb2
.dev_item
.devid
!= devinfo
.devid
)
963 if (memcmp(sb2
.dev_item
.uuid
, devinfo
.uuid
, sizeof devinfo
.uuid
))
966 if (memcmp(sb2
.dev_item
.fsid
, fsinfo
.fsid
, sizeof fsinfo
.fsid
))
969 return 0; /* It's good! */
972 static const char *find_device_btrfs(const char *path
)
975 struct btrfs_ioctl_fs_info_args fsinfo
;
976 static struct btrfs_ioctl_dev_info_args devinfo
;
977 const char *rv
= NULL
;
981 pfd
= open(path
, O_RDONLY
);
985 if (ioctl(pfd
, BTRFS_IOC_FS_INFO
, &fsinfo
))
988 /* We do not support multi-device btrfs yet */
989 if (fsinfo
.num_devices
!= 1)
992 /* The one device will have the max devid */
993 memset(&devinfo
, 0, sizeof devinfo
);
994 devinfo
.devid
= fsinfo
.max_id
;
995 if (ioctl(pfd
, BTRFS_IOC_DEV_INFO
, &devinfo
))
998 if (devinfo
.path
[0] != '/')
1001 dfd
= open((const char *)devinfo
.path
, O_RDONLY
);
1005 if (!validate_device_btrfs(pfd
, dfd
))
1006 rv
= (const char *)devinfo
.path
; /* It's good! */
1016 static const char *get_devname(const char *path
)
1018 const char *devname
= NULL
;
1022 if (stat(path
, &st
) || !S_ISDIR(st
.st_mode
)) {
1023 fprintf(stderr
, "%s: Not a directory: %s\n", program
, path
);
1026 if (statfs(path
, &sfs
)) {
1027 fprintf(stderr
, "%s: statfs %s: %s\n", program
, path
, strerror(errno
));
1032 devname
= opt
.device
;
1035 if (fs_type
== BTRFS
) {
1036 /* For btrfs try to get the device name from btrfs itself */
1037 devname
= find_device_btrfs(path
);
1042 devname
= find_device_mountinfo(path
, st
.st_dev
);
1047 devname
= find_device_sysfs(st
.st_dev
);
1050 /* klibc doesn't have getmntent and friends; instead, just create
1051 a new device with the appropriate device type */
1052 snprintf(devname_buf
, sizeof devname_buf
, "/tmp/dev-%u:%u",
1053 major(st
.st_dev
), minor(st
.st_dev
));
1055 if (mknod(devname_buf
, S_IFBLK
| 0600, st
.st_dev
)) {
1056 fprintf(stderr
, "%s: cannot create device %s\n", program
, devname
);
1060 atexit(device_cleanup
); /* unlink the device node on exit */
1061 devname
= devname_buf
;
1066 devname
= find_device("/proc/mounts", st
.st_dev
);
1069 /* Didn't find it in /proc/mounts, try /etc/mtab */
1070 devname
= find_device("/etc/mtab", st
.st_dev
);
1073 devname
= find_device_sysfs(st
.st_dev
);
1075 fprintf(stderr
, "%s: cannot find device for path %s\n", program
, path
);
1079 fprintf(stderr
, "%s is device %s\n", path
, devname
);
1085 static int open_device(const char *path
, struct stat
*st
, const char **_devname
)
1088 const char *devname
= NULL
;
1092 if (stat(path
, st
) || !S_ISDIR(st
->st_mode
)) {
1093 fprintf(stderr
, "%s: Not a directory: %s\n", program
, path
);
1097 if (statfs(path
, &sfs
)) {
1098 fprintf(stderr
, "%s: statfs %s: %s\n", program
, path
, strerror(errno
));
1101 if (sfs
.f_type
== EXT2_SUPER_MAGIC
)
1103 else if (sfs
.f_type
== BTRFS_SUPER_MAGIC
)
1105 else if (sfs
.f_type
== MSDOS_SUPER_MAGIC
)
1107 else if (sfs
.f_type
== NTFS_SB_MAGIC
||
1108 sfs
.f_type
== FUSE_SUPER_MAGIC
/* ntfs-3g */)
1112 fprintf(stderr
, "%s: not a fat, ntfs, ext2/3/4 or btrfs filesystem: %s\n",
1118 devname
= get_devname(path
);
1120 *_devname
= devname
;
1122 if ((devfd
= open(devname
, O_RDWR
| O_SYNC
)) < 0) {
1123 fprintf(stderr
, "%s: cannot open device %s\n", program
, devname
);
1127 /* Verify that the device we opened is the device intended */
1128 if (validate_device(path
, devfd
)) {
1129 fprintf(stderr
, "%s: path %s doesn't match device %s\n",
1130 program
, path
, devname
);
1137 static int btrfs_read_adv(int devfd
)
1139 if (xpread(devfd
, syslinux_adv
, 2 * ADV_SIZE
, BTRFS_ADV_OFFSET
)
1143 return syslinux_validate_adv(syslinux_adv
) ? 1 : 0;
1146 static int ext_read_adv(const char *path
, int devfd
, const char **namep
)
1151 if (fs_type
== BTRFS
) {
1152 /* btrfs "ldlinux.sys" is in 64k blank area */
1153 return btrfs_read_adv(devfd
);
1155 err
= read_adv(path
, name
= "ldlinux.sys");
1156 if (err
== 2) /* ldlinux.sys does not exist */
1157 err
= read_adv(path
, name
= "extlinux.sys");
1164 static int ext_write_adv(const char *path
, const char *cfg
, int devfd
)
1166 if (fs_type
== BTRFS
) { /* btrfs "ldlinux.sys" is in 64k blank area */
1167 if (xpwrite(devfd
, syslinux_adv
, 2 * ADV_SIZE
,
1168 BTRFS_ADV_OFFSET
) != 2 * ADV_SIZE
) {
1169 perror("writing adv");
1174 return write_adv(path
, cfg
);
1177 int install_loader(const char *path
, int update_only
)
1179 struct stat st
, fst
;
1181 const char *devname
;
1183 devfd
= open_device(path
, &st
, &devname
);
1187 if (update_only
&& !syslinux_already_installed(devfd
)) {
1188 fprintf(stderr
, "%s: no previous syslinux boot sector found\n",
1194 /* Read a pre-existing ADV, if already installed */
1195 if (opt
.reset_adv
) {
1196 syslinux_reset_adv(syslinux_adv
);
1197 } else if (ext_read_adv(path
, devfd
, NULL
) < 0) {
1202 if (modify_adv() < 0) {
1207 /* Install ldlinux.sys */
1208 if (install_file(path
, devfd
, &fst
)) {
1212 if (fst
.st_dev
!= st
.st_dev
) {
1213 fprintf(stderr
, "%s: file system changed under us - aborting!\n",
1220 rv
= install_bootblock(devfd
, devname
);
1228 * Modify the ADV of an existing installation
1230 int modify_existing_adv(const char *path
)
1232 const char *filename
;
1235 devfd
= open_device(path
, NULL
, NULL
);
1240 syslinux_reset_adv(syslinux_adv
);
1241 else if (ext_read_adv(path
, devfd
, &filename
) < 0) {
1245 if (modify_adv() < 0) {
1249 if (ext_write_adv(path
, filename
, devfd
) < 0) {
1257 int main(int argc
, char *argv
[])
1259 parse_options(argc
, argv
, MODE_EXTLINUX
);
1261 if (!opt
.directory
|| opt
.install_mbr
|| opt
.activate_partition
)
1264 if (opt
.update_only
== -1) {
1265 if (opt
.reset_adv
|| opt
.set_once
|| opt
.menu_save
)
1266 return modify_existing_adv(opt
.directory
);
1268 usage(EX_USAGE
, MODE_EXTLINUX
);
1271 return install_loader(opt
.directory
, opt
.update_only
);