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 */
57 # define dprintf printf
59 # define dprintf(...) ((void)0)
62 #ifndef EXT2_SUPER_OFFSET
63 #define EXT2_SUPER_OFFSET 1024
66 /* the btrfs partition first 64K blank area is used to store boot sector and
67 boot image, the boot sector is from 0~512, the boot image starts after */
68 #define BTRFS_BOOTSECT_AREA 65536
69 #define BTRFS_EXTLINUX_OFFSET SECTOR_SIZE
70 #define BTRFS_SUBVOL_MAX 256 /* By btrfs specification */
71 static char subvol
[BTRFS_SUBVOL_MAX
];
73 #define BTRFS_ADV_OFFSET (BTRFS_BOOTSECT_AREA - 2 * ADV_SIZE)
76 * Get the size of a block device
78 uint64_t get_size(int devfd
)
85 if (!ioctl(devfd
, BLKGETSIZE64
, &bytes
))
88 if (!ioctl(devfd
, BLKGETSIZE
, §s
))
89 return (uint64_t) sects
<< 9;
90 else if (!fstat(devfd
, &st
) && st
.st_size
)
97 * Get device geometry and partition offset
99 struct geometry_table
{
101 struct hd_geometry g
;
104 static int sysfs_get_offset(int devfd
, unsigned long *start
)
107 char sysfs_name
[128];
111 if (fstat(devfd
, &st
))
114 if ((size_t)snprintf(sysfs_name
, sizeof sysfs_name
,
115 "/sys/dev/block/%u:%u/start",
116 major(st
.st_rdev
), minor(st
.st_rdev
))
117 >= sizeof sysfs_name
)
120 f
= fopen(sysfs_name
, "r");
124 rv
= fscanf(f
, "%lu", start
);
127 return (rv
== 1) ? 0 : -1;
130 /* Standard floppy disk geometries, plus LS-120. Zipdisk geometry
131 (x/64/32) is the final fallback. I don't know what LS-240 has
132 as its geometry, since I don't have one and don't know anyone that does,
133 and Google wasn't helpful... */
134 static const struct geometry_table standard_geometries
[] = {
135 {360 * 1024, {2, 9, 40, 0}},
136 {720 * 1024, {2, 9, 80, 0}},
137 {1200 * 1024, {2, 15, 80, 0}},
138 {1440 * 1024, {2, 18, 80, 0}},
139 {1680 * 1024, {2, 21, 80, 0}},
140 {1722 * 1024, {2, 21, 80, 0}},
141 {2880 * 1024, {2, 36, 80, 0}},
142 {3840 * 1024, {2, 48, 80, 0}},
143 {123264 * 1024, {8, 32, 963, 0}}, /* LS120 */
147 int get_geometry(int devfd
, uint64_t totalbytes
, struct hd_geometry
*geo
)
149 struct floppy_struct fd_str
;
151 struct loop_info64 li64
;
152 const struct geometry_table
*gp
;
155 memset(geo
, 0, sizeof *geo
);
157 if (!ioctl(devfd
, HDIO_GETGEO
, geo
)) {
159 } else if (!ioctl(devfd
, FDGETPRM
, &fd_str
)) {
160 geo
->heads
= fd_str
.head
;
161 geo
->sectors
= fd_str
.sect
;
162 geo
->cylinders
= fd_str
.track
;
167 /* Didn't work. Let's see if this is one of the standard geometries */
168 for (gp
= standard_geometries
; gp
->bytes
; gp
++) {
169 if (gp
->bytes
== totalbytes
) {
170 memcpy(geo
, &gp
->g
, sizeof *geo
);
175 /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is
176 what zipdisks use, so this would help if someone has a USB key that
177 they're booting in USB-ZIP mode. */
179 geo
->heads
= opt
.heads
? : 64;
180 geo
->sectors
= opt
.sectors
? : 32;
181 geo
->cylinders
= totalbytes
/ (geo
->heads
* geo
->sectors
<< SECTOR_SHIFT
);
184 if (!opt
.sectors
&& !opt
.heads
) {
186 "Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n"
187 " (on hard disks, this is usually harmless.)\n",
188 geo
->heads
, geo
->sectors
);
189 rv
= 1; /* Suboptimal result */
193 /* If this is a loopback device, try to set the start */
194 if (!ioctl(devfd
, LOOP_GET_STATUS64
, &li64
))
195 geo
->start
= li64
.lo_offset
>> SECTOR_SHIFT
;
196 else if (!ioctl(devfd
, LOOP_GET_STATUS
, &li
))
197 geo
->start
= (unsigned int)li
.lo_offset
>> SECTOR_SHIFT
;
198 else if (!sysfs_get_offset(devfd
, &geo
->start
)) {
206 * Query the device geometry and put it into the boot sector.
207 * Map the file and put the map in the boot sector and file.
208 * Stick the "current directory" inode number into the file.
210 * Returns the number of modified bytes in the boot file.
212 int patch_file_and_bootblock(int fd
, const char *dir
, int devfd
)
214 struct stat dirst
, xdst
;
215 struct hd_geometry geo
;
217 uint64_t totalbytes
, totalsectors
;
219 struct fat_boot_sector
*sbs
;
220 char *dirpath
, *subpath
, *xdirpath
;
223 dirpath
= realpath(dir
, NULL
);
224 if (!dirpath
|| stat(dir
, &dirst
)) {
225 perror("accessing install directory");
226 exit(255); /* This should never happen */
229 if (lstat(dirpath
, &xdst
) ||
230 dirst
.st_ino
!= xdst
.st_ino
||
231 dirst
.st_dev
!= xdst
.st_dev
) {
232 perror("realpath returned nonsense");
236 subpath
= strchr(dirpath
, '\0');
238 if (*subpath
== '/') {
239 if (subpath
> dirpath
) {
245 if (lstat(xdirpath
, &xdst
) || dirst
.st_dev
!= xdst
.st_dev
) {
246 subpath
= strchr(subpath
+1, '/');
248 subpath
= "/"; /* It's the root of the filesystem */
254 if (subpath
== dirpath
)
260 /* Now subpath should contain the path relative to the fs base */
261 dprintf("subpath = %s\n", subpath
);
263 totalbytes
= get_size(devfd
);
264 get_geometry(devfd
, totalbytes
, &geo
);
267 geo
.heads
= opt
.heads
;
269 geo
.sectors
= opt
.sectors
;
271 /* Patch this into a fake FAT superblock. This isn't because
272 FAT is a good format in any way, it's because it lets the
273 early bootstrap share code with the FAT version. */
274 dprintf("heads = %u, sect = %u\n", geo
.heads
, geo
.sectors
);
276 sbs
= (struct fat_boot_sector
*)syslinux_bootsect
;
278 totalsectors
= totalbytes
>> SECTOR_SHIFT
;
279 if (totalsectors
>= 65536) {
280 set_16(&sbs
->bsSectors
, 0);
282 set_16(&sbs
->bsSectors
, totalsectors
);
284 set_32(&sbs
->bsHugeSectors
, totalsectors
);
286 set_16(&sbs
->bsBytesPerSec
, SECTOR_SIZE
);
287 set_16(&sbs
->bsSecPerTrack
, geo
.sectors
);
288 set_16(&sbs
->bsHeads
, geo
.heads
);
289 set_32(&sbs
->bsHiddenSecs
, geo
.start
);
291 /* Construct the boot file map */
293 dprintf("directory inode = %lu\n", (unsigned long)dirst
.st_ino
);
294 nsect
= (boot_image_len
+ SECTOR_SIZE
- 1) >> SECTOR_SHIFT
;
295 nsect
+= 2; /* Two sectors for the ADV */
296 sectp
= alloca(sizeof(sector_t
) * nsect
);
297 if (fs_type
== EXT2
|| fs_type
== VFAT
|| fs_type
== NTFS
) {
298 if (sectmap(fd
, sectp
, nsect
)) {
302 } else if (fs_type
== BTRFS
) {
304 sector_t
*sp
= sectp
;
306 for (i
= 0; i
< nsect
- 2; i
++)
307 *sp
++ = BTRFS_EXTLINUX_OFFSET
/SECTOR_SIZE
+ i
;
308 for (i
= 0; i
< 2; i
++)
309 *sp
++ = BTRFS_ADV_OFFSET
/SECTOR_SIZE
+ i
;
312 /* Create the modified image in memory */
313 rv
= syslinux_patch(sectp
, nsect
, opt
.stupid_mode
,
314 opt
.raid_mode
, subpath
, subvol
);
321 * Install the boot block on the specified device.
322 * Must be run AFTER install_file()!
324 int install_bootblock(int fd
, const char *device
)
326 struct ext2_super_block sb
;
327 struct btrfs_super_block sb2
;
328 struct fat_boot_sector sb3
;
329 struct ntfs_boot_sector sb4
;
332 if (fs_type
== EXT2
) {
333 if (xpread(fd
, &sb
, sizeof sb
, EXT2_SUPER_OFFSET
) != sizeof sb
) {
334 perror("reading superblock");
337 if (sb
.s_magic
== EXT2_SUPER_MAGIC
)
339 } else if (fs_type
== BTRFS
) {
340 if (xpread(fd
, &sb2
, sizeof sb2
, BTRFS_SUPER_INFO_OFFSET
)
342 perror("reading superblock");
345 if (sb2
.magic
== *(u64
*)BTRFS_MAGIC
)
347 } else if (fs_type
== VFAT
) {
348 if (xpread(fd
, &sb3
, sizeof sb3
, 0) != sizeof sb3
) {
349 perror("reading fat superblock");
352 if (fat_check_sb_fields(&sb3
))
354 } else if (fs_type
== NTFS
) {
355 if (xpread(fd
, &sb4
, sizeof(sb4
), 0) != sizeof(sb4
)) {
356 perror("reading ntfs superblock");
360 if (ntfs_check_sb_fields(&sb4
))
364 fprintf(stderr
, "no fat, ntfs, ext2/3/4 or btrfs superblock found on %s\n",
368 if (fs_type
== VFAT
) {
369 struct fat_boot_sector
*sbs
= (struct fat_boot_sector
*)syslinux_bootsect
;
370 if (xpwrite(fd
, &sbs
->FAT_bsHead
, FAT_bsHeadLen
, 0) != FAT_bsHeadLen
||
371 xpwrite(fd
, &sbs
->FAT_bsCode
, FAT_bsCodeLen
,
372 offsetof(struct fat_boot_sector
, FAT_bsCode
)) != FAT_bsCodeLen
) {
373 perror("writing fat bootblock");
376 } else if (fs_type
== NTFS
) {
377 struct ntfs_boot_sector
*sbs
=
378 (struct ntfs_boot_sector
*)syslinux_bootsect
;
379 if (xpwrite(fd
, &sbs
->NTFS_bsHead
,
380 NTFS_bsHeadLen
, 0) != NTFS_bsHeadLen
||
381 xpwrite(fd
, &sbs
->NTFS_bsCode
, NTFS_bsCodeLen
,
382 offsetof(struct ntfs_boot_sector
,
383 NTFS_bsCode
)) != NTFS_bsCodeLen
) {
384 perror("writing ntfs bootblock");
388 if (xpwrite(fd
, syslinux_bootsect
, syslinux_bootsect_len
, 0)
389 != syslinux_bootsect_len
) {
390 perror("writing bootblock");
398 int ext2_fat_install_file(const char *path
, int devfd
, struct stat
*rst
)
400 char *file
, *oldfile
;
401 int fd
= -1, dirfd
= -1;
405 r1
= asprintf(&file
, "%s%sldlinux.sys",
406 path
, path
[0] && path
[strlen(path
) - 1] == '/' ? "" : "/");
407 r2
= asprintf(&oldfile
, "%s%sextlinux.sys",
408 path
, path
[0] && path
[strlen(path
) - 1] == '/' ? "" : "/");
409 if (r1
< 0 || !file
|| r2
< 0 || !oldfile
) {
414 dirfd
= open(path
, O_RDONLY
| O_DIRECTORY
);
420 fd
= open(file
, O_RDONLY
);
422 if (errno
!= ENOENT
) {
427 clear_attributes(fd
);
431 fd
= open(file
, O_WRONLY
| O_TRUNC
| O_CREAT
| O_SYNC
,
432 S_IRUSR
| S_IRGRP
| S_IROTH
);
438 /* Write it the first time */
439 if (xpwrite(fd
, boot_image
, boot_image_len
, 0) != boot_image_len
||
440 xpwrite(fd
, syslinux_adv
, 2 * ADV_SIZE
,
441 boot_image_len
) != 2 * ADV_SIZE
) {
442 fprintf(stderr
, "%s: write failure on %s\n", program
, file
);
446 /* Map the file, and patch the initial sector accordingly */
447 modbytes
= patch_file_and_bootblock(fd
, path
, devfd
);
449 /* Write the patch area again - this relies on the file being
450 overwritten in place! */
451 if (xpwrite(fd
, boot_image
, modbytes
, 0) != modbytes
) {
452 fprintf(stderr
, "%s: write failure on %s\n", program
, file
);
456 /* Attempt to set immutable flag and remove all write access */
457 /* Only set immutable flag if file is owned by root */
460 if (fstat(fd
, rst
)) {
468 /* Look if we have the old filename */
469 fd
= open(oldfile
, O_RDONLY
);
471 clear_attributes(fd
);
491 /* btrfs has to install the ldlinux.sys in the first 64K blank area, which
492 is not managered by btrfs tree, so actually this is not installed as files.
493 since the cow feature of btrfs will move the ldlinux.sys every where */
494 int btrfs_install_file(const char *path
, int devfd
, struct stat
*rst
)
496 patch_file_and_bootblock(-1, path
, devfd
);
497 if (xpwrite(devfd
, boot_image
, boot_image_len
, BTRFS_EXTLINUX_OFFSET
)
499 perror("writing bootblock");
502 dprintf("write boot_image to 0x%x\n", BTRFS_EXTLINUX_OFFSET
);
503 if (xpwrite(devfd
, syslinux_adv
, 2 * ADV_SIZE
, BTRFS_ADV_OFFSET
)
505 perror("writing adv");
508 dprintf("write adv to 0x%x\n", BTRFS_ADV_OFFSET
);
509 if (stat(path
, rst
)) {
517 * * test if path is a subvolume:
518 * * this function return
519 * * 0-> path exists but it is not a subvolume
520 * * 1-> path exists and it is a subvolume
521 * * -1 -> path is unaccessible
523 static int test_issubvolume(char *path
)
529 res
= stat(path
, &st
);
533 return (st
.st_ino
== 256) && S_ISDIR(st
.st_mode
);
538 * Get file handle for a file or dir
540 static int open_file_or_dir(const char *fname
)
547 ret
= stat(fname
, &st
);
551 if (S_ISDIR(st
.st_mode
)) {
552 dirstream
= opendir(fname
);
556 fd
= dirfd(dirstream
);
558 fd
= open(fname
, O_RDWR
);
567 * Get the default subvolume of a btrfs filesystem
568 * rootdir: btrfs root dir
569 * subvol: this function will save the default subvolume name here
571 static char * get_default_subvol(char * rootdir
, char * subvol
)
573 struct btrfs_ioctl_search_args args
;
574 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
575 struct btrfs_ioctl_search_header
*sh
;
578 struct btrfs_root_ref
*ref
;
579 struct btrfs_dir_item
*dir_item
;
580 unsigned long off
= 0;
584 u64 defaultsubvolid
= 0;
586 ret
= test_issubvolume(rootdir
);
588 fd
= open_file_or_dir(rootdir
);
590 fprintf(stderr
, "ERROR: failed to open %s\n", rootdir
);
599 memset(&args
, 0, sizeof(args
));
601 /* search in the tree of tree roots */
605 * set the min and max to backref keys. The search will
606 * only send back this type of key now.
608 sk
->max_type
= BTRFS_DIR_ITEM_KEY
;
609 sk
->min_type
= BTRFS_DIR_ITEM_KEY
;
612 * set all the other params to the max, we'll take any objectid
615 sk
->min_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
616 sk
->max_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
618 sk
->max_offset
= (u64
)-1;
620 sk
->max_transid
= (u64
)-1;
622 /* just a big number, doesn't matter much */
626 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
628 fprintf(stderr
, "ERROR: can't perform the search\n");
632 /* the ioctl returns the number of item it found in nr_items */
633 if (sk
->nr_items
== 0) {
640 * for each item, pull the key out of the header and then
641 * read the root_ref item it contains
643 for (i
= 0; i
< sk
->nr_items
; i
++) {
644 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+ off
);
646 if (sh
->type
== BTRFS_DIR_ITEM_KEY
) {
647 dir_item
= (struct btrfs_dir_item
*)(args
.buf
+ off
);
648 name_len
= dir_item
->name_len
;
649 name
= (char *)(dir_item
+ 1);
652 /*add_root(&root_lookup, sh->objectid, sh->offset,
653 dir_id, name, name_len);*/
654 strncpy(dirname
, name
, name_len
);
655 dirname
[name_len
] = '\0';
656 if (strcmp(dirname
, "default") == 0) {
657 defaultsubvolid
= dir_item
->location
.objectid
;
664 * record the mins in sk so we can make sure the
665 * next search doesn't repeat this root
667 sk
->min_objectid
= sh
->objectid
;
668 sk
->min_type
= sh
->type
;
669 sk
->max_type
= sh
->type
;
670 sk
->min_offset
= sh
->offset
;
672 if (defaultsubvolid
!= 0)
675 /* this iteration is done, step forward one root for the next
678 if (sk
->min_objectid
< (u64
)-1) {
679 sk
->min_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
680 sk
->max_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
681 sk
->max_type
= BTRFS_ROOT_BACKREF_KEY
;
682 sk
->min_type
= BTRFS_ROOT_BACKREF_KEY
;
688 if (defaultsubvolid
== 0) {
693 memset(&args
, 0, sizeof(args
));
695 /* search in the tree of tree roots */
699 * set the min and max to backref keys. The search will
700 * only send back this type of key now.
702 sk
->max_type
= BTRFS_ROOT_BACKREF_KEY
;
703 sk
->min_type
= BTRFS_ROOT_BACKREF_KEY
;
706 * set all the other params to the max, we'll take any objectid
709 sk
->max_objectid
= (u64
)-1;
710 sk
->max_offset
= (u64
)-1;
711 sk
->max_transid
= (u64
)-1;
713 /* just a big number, doesn't matter much */
717 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
719 fprintf(stderr
, "ERROR: can't perform the search\n");
723 /* the ioctl returns the number of item it found in nr_items */
724 if (sk
->nr_items
== 0)
730 * for each item, pull the key out of the header and then
731 * read the root_ref item it contains
733 for (i
= 0; i
< sk
->nr_items
; i
++) {
734 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+ off
);
736 if (sh
->type
== BTRFS_ROOT_BACKREF_KEY
) {
737 ref
= (struct btrfs_root_ref
*)(args
.buf
+ off
);
738 name_len
= ref
->name_len
;
739 name
= (char *)(ref
+ 1);
741 if (sh
->objectid
== defaultsubvolid
) {
742 strncpy(subvol
, name
, name_len
);
743 subvol
[name_len
] = '\0';
744 dprintf("The default subvolume: %s, ID: %llu\n",
745 subvol
, sh
->objectid
);
754 * record the mins in sk so we can make sure the
755 * next search doesn't repeat this root
757 sk
->min_objectid
= sh
->objectid
;
758 sk
->min_type
= sh
->type
;
759 sk
->min_offset
= sh
->offset
;
761 if (subvol
[0] != '\0')
764 /* this iteration is done, step forward one root for the next
767 if (sk
->min_objectid
< (u64
)-1) {
769 sk
->min_type
= BTRFS_ROOT_BACKREF_KEY
;
777 int install_file(const char *path
, int devfd
, struct stat
*rst
)
779 if (fs_type
== EXT2
|| fs_type
== VFAT
|| fs_type
== NTFS
)
780 return ext2_fat_install_file(path
, devfd
, rst
);
781 else if (fs_type
== BTRFS
)
782 return btrfs_install_file(path
, devfd
, rst
);
787 static char devname_buf
[64];
789 static void device_cleanup(void)
795 /* Verify that a device fd and a pathname agree.
796 Return 0 on valid, -1 on error. */
797 static int validate_device(const char *path
, int devfd
)
799 struct stat pst
, dst
;
802 if (stat(path
, &pst
) || fstat(devfd
, &dst
) || statfs(path
, &sfs
))
804 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
805 if (fs_type
== BTRFS
&& sfs
.f_type
== BTRFS_SUPER_MAGIC
)
807 return (pst
.st_dev
== dst
.st_rdev
) ? 0 : -1;
811 static const char *find_device(const char *mtab_file
, dev_t dev
)
816 const char *devname
= NULL
;
819 mtab
= setmntent(mtab_file
, "r");
824 while ((mnt
= getmntent(mtab
))) {
825 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
828 if (!strcmp(mnt
->mnt_type
, "btrfs") &&
829 !stat(mnt
->mnt_dir
, &dst
) &&
832 get_default_subvol(mnt
->mnt_dir
, subvol
);
837 if ((!strcmp(mnt
->mnt_type
, "ext2") ||
838 !strcmp(mnt
->mnt_type
, "ext3") ||
839 !strcmp(mnt
->mnt_type
, "ext4")) &&
840 !stat(mnt
->mnt_fsname
, &dst
) &&
841 dst
.st_rdev
== dev
) {
846 if ((!strcmp(mnt
->mnt_type
, "vfat")) &&
847 !stat(mnt
->mnt_fsname
, &dst
) &&
848 dst
.st_rdev
== dev
) {
853 if ((!strcmp(mnt
->mnt_type
, "fuseblk") /* ntfs-3g */ ||
854 !strcmp(mnt
->mnt_type
, "ntfs")) &&
855 !stat(mnt
->mnt_fsname
, &dst
) &&
856 dst
.st_rdev
== dev
) {
866 devname
= strdup(mnt
->mnt_fsname
);
877 * On newer Linux kernels we can use sysfs to get a backwards mapping
878 * from device names to standard filenames
880 static const char *find_device_sysfs(dev_t dev
)
883 char linkname
[PATH_MAX
];
889 snprintf(sysname
, sizeof sysname
, "/sys/dev/block/%u:%u",
890 major(dev
), minor(dev
));
892 llen
= readlink(sysname
, linkname
, sizeof linkname
);
893 if (llen
< 0 || llen
>= sizeof linkname
)
896 linkname
[llen
] = '\0';
898 p
= strrchr(linkname
, '/');
899 p
= p
? p
+1 : linkname
; /* Leave basename */
901 buf
= q
= malloc(strlen(p
) + 6);
905 memcpy(q
, "/dev/", 5);
909 *q
++ = (*p
== '!') ? '/' : *p
;
915 if (!stat(buf
, &st
) && st
.st_dev
== dev
)
916 return buf
; /* Found it! */
924 static const char *get_devname(const char *path
)
926 const char *devname
= NULL
;
930 if (stat(path
, &st
) || !S_ISDIR(st
.st_mode
)) {
931 fprintf(stderr
, "%s: Not a directory: %s\n", program
, path
);
934 if (statfs(path
, &sfs
)) {
935 fprintf(stderr
, "%s: statfs %s: %s\n", program
, path
, strerror(errno
));
941 devname
= find_device_sysfs(st
.st_dev
);
944 /* klibc doesn't have getmntent and friends; instead, just create
945 a new device with the appropriate device type */
946 snprintf(devname_buf
, sizeof devname_buf
, "/tmp/dev-%u:%u",
947 major(st
.st_dev
), minor(st
.st_dev
));
949 if (mknod(devname_buf
, S_IFBLK
| 0600, st
.st_dev
)) {
950 fprintf(stderr
, "%s: cannot create device %s\n", program
, devname
);
954 atexit(device_cleanup
); /* unlink the device node on exit */
955 devname
= devname_buf
;
960 devname
= find_device("/proc/mounts", st
.st_dev
);
962 /* Didn't find it in /proc/mounts, try /etc/mtab */
963 devname
= find_device("/etc/mtab", st
.st_dev
);
966 devname
= find_device_sysfs(st
.st_dev
);
968 fprintf(stderr
, "%s: cannot find device for path %s\n", program
, path
);
972 fprintf(stderr
, "%s is device %s\n", path
, devname
);
978 static int open_device(const char *path
, struct stat
*st
, const char **_devname
)
981 const char *devname
= NULL
;
985 if (stat(path
, st
) || !S_ISDIR(st
->st_mode
)) {
986 fprintf(stderr
, "%s: Not a directory: %s\n", program
, path
);
990 if (statfs(path
, &sfs
)) {
991 fprintf(stderr
, "%s: statfs %s: %s\n", program
, path
, strerror(errno
));
994 if (sfs
.f_type
== EXT2_SUPER_MAGIC
)
996 else if (sfs
.f_type
== BTRFS_SUPER_MAGIC
)
998 else if (sfs
.f_type
== MSDOS_SUPER_MAGIC
)
1000 else if (sfs
.f_type
== NTFS_SB_MAGIC
||
1001 sfs
.f_type
== FUSE_SUPER_MAGIC
/* ntfs-3g */)
1005 fprintf(stderr
, "%s: not a fat, ntfs, ext2/3/4 or btrfs filesystem: %s\n",
1011 devname
= get_devname(path
);
1013 *_devname
= devname
;
1015 if ((devfd
= open(devname
, O_RDWR
| O_SYNC
)) < 0) {
1016 fprintf(stderr
, "%s: cannot open device %s\n", program
, devname
);
1020 /* Verify that the device we opened is the device intended */
1021 if (validate_device(path
, devfd
)) {
1022 fprintf(stderr
, "%s: path %s doesn't match device %s\n",
1023 program
, path
, devname
);
1030 static int btrfs_read_adv(int devfd
)
1032 if (xpread(devfd
, syslinux_adv
, 2 * ADV_SIZE
, BTRFS_ADV_OFFSET
)
1036 return syslinux_validate_adv(syslinux_adv
) ? 1 : 0;
1039 static int ext_read_adv(const char *path
, int devfd
, const char **namep
)
1044 if (fs_type
== BTRFS
) {
1045 /* btrfs "ldlinux.sys" is in 64k blank area */
1046 return btrfs_read_adv(devfd
);
1048 err
= read_adv(path
, name
= "ldlinux.sys");
1049 if (err
== 2) /* ldlinux.sys does not exist */
1050 err
= read_adv(path
, name
= "extlinux.sys");
1057 static int ext_write_adv(const char *path
, const char *cfg
, int devfd
)
1059 if (fs_type
== BTRFS
) { /* btrfs "ldlinux.sys" is in 64k blank area */
1060 if (xpwrite(devfd
, syslinux_adv
, 2 * ADV_SIZE
,
1061 BTRFS_ADV_OFFSET
) != 2 * ADV_SIZE
) {
1062 perror("writing adv");
1067 return write_adv(path
, cfg
);
1070 int install_loader(const char *path
, int update_only
)
1072 struct stat st
, fst
;
1074 const char *devname
;
1076 devfd
= open_device(path
, &st
, &devname
);
1080 if (update_only
&& !syslinux_already_installed(devfd
)) {
1081 fprintf(stderr
, "%s: no previous syslinux boot sector found\n",
1087 /* Read a pre-existing ADV, if already installed */
1088 if (opt
.reset_adv
) {
1089 syslinux_reset_adv(syslinux_adv
);
1090 } else if (ext_read_adv(path
, devfd
, NULL
) < 0) {
1095 if (modify_adv() < 0) {
1100 /* Install ldlinux.sys */
1101 if (install_file(path
, devfd
, &fst
)) {
1105 if (fst
.st_dev
!= st
.st_dev
) {
1106 fprintf(stderr
, "%s: file system changed under us - aborting!\n",
1113 rv
= install_bootblock(devfd
, devname
);
1121 * Modify the ADV of an existing installation
1123 int modify_existing_adv(const char *path
)
1125 const char *filename
;
1128 devfd
= open_device(path
, NULL
, NULL
);
1133 syslinux_reset_adv(syslinux_adv
);
1134 else if (ext_read_adv(path
, devfd
, &filename
) < 0) {
1138 if (modify_adv() < 0) {
1142 if (ext_write_adv(path
, filename
, devfd
) < 0) {
1150 int main(int argc
, char *argv
[])
1152 parse_options(argc
, argv
, MODE_EXTLINUX
);
1154 if (!opt
.directory
|| opt
.install_mbr
|| opt
.activate_partition
)
1157 if (opt
.update_only
== -1) {
1158 if (opt
.reset_adv
|| opt
.set_once
|| opt
.menu_save
)
1159 return modify_existing_adv(opt
.directory
);
1161 usage(EX_USAGE
, MODE_EXTLINUX
);
1164 return install_loader(opt
.directory
, opt
.update_only
);