extlinux/main.c: Correct comment about btrfs install
[syslinux.git] / extlinux / main.c
blobe2eb7281eac8cb6b6b33e8f137838885e7a990dd
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 * ----------------------------------------------------------------------- */
15 * extlinux.c
17 * Install the syslinux boot block on a fat, ntfs, ext2/3/4, btrfs, xfs,
18 * and ufs1/2 filesystem.
21 #define _GNU_SOURCE /* Enable everything */
22 #include <inttypes.h>
23 /* This is needed to deal with the kernel headers imported into glibc 3.3.3. */
24 #include <alloca.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <dirent.h>
30 #ifndef __KLIBC__
31 #include <mntent.h>
32 #endif
33 #include <stdbool.h>
34 #include <stddef.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <getopt.h>
38 #include <sysexits.h>
39 #include <sys/ioctl.h>
40 #include <sys/stat.h>
41 #include <sys/types.h>
42 #include <sys/mount.h>
43 #include <sys/vfs.h>
45 #include "linuxioctl.h"
47 #include "btrfs.h"
48 #include "fat.h"
49 #include "ntfs.h"
50 #include "xfs.h"
51 #include "xfs_types.h"
52 #include "xfs_sb.h"
53 #include "ufs.h"
54 #include "ufs_fs.h"
55 #include "misc.h"
56 #include "version.h"
57 #include "syslxint.h"
58 #include "syslxcom.h" /* common functions shared with extlinux and syslinux */
59 #include "syslxrw.h"
60 #include "syslxfs.h"
61 #include "setadv.h"
62 #include "syslxopt.h" /* unified options */
63 #include "mountinfo.h"
65 #ifdef DEBUG
66 # define dprintf printf
67 #else
68 # define dprintf(...) ((void)0)
69 #endif
71 #ifndef EXT2_SUPER_OFFSET
72 #define EXT2_SUPER_OFFSET 1024
73 #endif
75 /* Since we have unused 2048 bytes in the primary AG of an XFS partition,
76 * we will use the first 0~512 bytes starting from 2048 for the Syslinux
77 * boot sector.
79 #define XFS_BOOTSECT_OFFSET (4 << SECTOR_SHIFT)
80 #define XFS_SUPPORTED_BLOCKSIZE 4096 /* 4 KiB filesystem block size */
83 * btrfs has two discontiguous areas reserved for the boot loader.
84 * Use the first one (Boot Area A) for the boot sector and the ADV,
85 * and the second one for "ldlinux.sys".
87 #define BTRFS_EXTLINUX_OFFSET BTRFS_BOOT_AREA_B_OFFSET
88 #define BTRFS_EXTLINUX_SIZE BTRFS_BOOT_AREA_B_SIZE
89 #define BTRFS_SUBVOL_MAX 256 /* By btrfs specification */
90 static char subvol[BTRFS_SUBVOL_MAX];
92 #define BTRFS_ADV_OFFSET (BTRFS_BOOT_AREA_A_OFFSET + BTRFS_BOOT_AREA_A_SIZE \
93 - 2*ADV_SIZE)
96 * Get the size of a block device
98 static uint64_t get_size(int devfd)
100 uint64_t bytes;
101 uint32_t sects;
102 struct stat st;
104 #ifdef BLKGETSIZE64
105 if (!ioctl(devfd, BLKGETSIZE64, &bytes))
106 return bytes;
107 #endif
108 if (!ioctl(devfd, BLKGETSIZE, &sects))
109 return (uint64_t) sects << 9;
110 else if (!fstat(devfd, &st) && st.st_size)
111 return st.st_size;
112 else
113 return 0;
117 * Get device geometry and partition offset
119 struct geometry_table {
120 uint64_t bytes;
121 struct hd_geometry g;
124 static int sysfs_get_offset(int devfd, unsigned long *start)
126 struct stat st;
127 char sysfs_name[128];
128 FILE *f;
129 int rv;
131 if (fstat(devfd, &st))
132 return -1;
134 if ((size_t)snprintf(sysfs_name, sizeof sysfs_name,
135 "/sys/dev/block/%u:%u/start",
136 major(st.st_rdev), minor(st.st_rdev))
137 >= sizeof sysfs_name)
138 return -1;
140 f = fopen(sysfs_name, "r");
141 if (!f)
142 return -1;
144 rv = fscanf(f, "%lu", start);
145 fclose(f);
147 return (rv == 1) ? 0 : -1;
150 /* Standard floppy disk geometries, plus LS-120. Zipdisk geometry
151 (x/64/32) is the final fallback. I don't know what LS-240 has
152 as its geometry, since I don't have one and don't know anyone that does,
153 and Google wasn't helpful... */
154 static const struct geometry_table standard_geometries[] = {
155 {360 * 1024, {2, 9, 40, 0}},
156 {720 * 1024, {2, 9, 80, 0}},
157 {1200 * 1024, {2, 15, 80, 0}},
158 {1440 * 1024, {2, 18, 80, 0}},
159 {1680 * 1024, {2, 21, 80, 0}},
160 {1722 * 1024, {2, 21, 80, 0}},
161 {2880 * 1024, {2, 36, 80, 0}},
162 {3840 * 1024, {2, 48, 80, 0}},
163 {123264 * 1024, {8, 32, 963, 0}}, /* LS120 */
164 {0, {0, 0, 0, 0}}
167 int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo)
169 struct floppy_struct fd_str;
170 struct loop_info li;
171 struct loop_info64 li64;
172 const struct geometry_table *gp;
173 int rv = 0;
175 memset(geo, 0, sizeof *geo);
177 if (!ioctl(devfd, HDIO_GETGEO, geo)) {
178 goto ok;
179 } else if (!ioctl(devfd, FDGETPRM, &fd_str)) {
180 geo->heads = fd_str.head;
181 geo->sectors = fd_str.sect;
182 geo->cylinders = fd_str.track;
183 geo->start = 0;
184 goto ok;
187 /* Didn't work. Let's see if this is one of the standard geometries */
188 for (gp = standard_geometries; gp->bytes; gp++) {
189 if (gp->bytes == totalbytes) {
190 memcpy(geo, &gp->g, sizeof *geo);
191 goto ok;
195 /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is
196 what zipdisks use, so this would help if someone has a USB key that
197 they're booting in USB-ZIP mode. */
199 geo->heads = opt.heads ? : 64;
200 geo->sectors = opt.sectors ? : 32;
201 geo->cylinders = totalbytes / (geo->heads * geo->sectors << SECTOR_SHIFT);
202 geo->start = 0;
204 if (!opt.sectors && !opt.heads) {
205 fprintf(stderr,
206 "Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n"
207 " (on hard disks, this is usually harmless.)\n",
208 geo->heads, geo->sectors);
209 rv = 1; /* Suboptimal result */
213 /* If this is a loopback device, try to set the start */
214 if (!ioctl(devfd, LOOP_GET_STATUS64, &li64))
215 geo->start = li64.lo_offset >> SECTOR_SHIFT;
216 else if (!ioctl(devfd, LOOP_GET_STATUS, &li))
217 geo->start = (unsigned int)li.lo_offset >> SECTOR_SHIFT;
218 else if (!sysfs_get_offset(devfd, &geo->start)) {
219 /* OK */
222 return rv;
226 * Query the device geometry and put it into the boot sector.
227 * Map the file and put the map in the boot sector and file.
228 * Stick the "current directory" inode number into the file.
230 * Returns the number of modified bytes in the boot file.
232 static int patch_file_and_bootblock(int fd, const char *dir, int devfd)
234 struct stat dirst, xdst;
235 struct hd_geometry geo;
236 sector_t *sectp;
237 uint64_t totalbytes, totalsectors;
238 int nsect;
239 struct fat_boot_sector *sbs;
240 char *dirpath, *subpath, *xdirpath;
241 int rv;
243 dirpath = realpath(dir, NULL);
244 if (!dirpath || stat(dir, &dirst)) {
245 perror("accessing install directory");
246 exit(255); /* This should never happen */
249 if (lstat(dirpath, &xdst) ||
250 dirst.st_ino != xdst.st_ino ||
251 dirst.st_dev != xdst.st_dev) {
252 perror("realpath returned nonsense");
253 exit(255);
256 subpath = strchr(dirpath, '\0');
257 for (;;) {
258 if (*subpath == '/') {
259 if (subpath > dirpath) {
260 *subpath = '\0';
261 xdirpath = dirpath;
262 } else {
263 xdirpath = "/";
265 if (lstat(xdirpath, &xdst) || dirst.st_dev != xdst.st_dev) {
266 subpath = strchr(subpath+1, '/');
267 if (!subpath)
268 subpath = "/"; /* It's the root of the filesystem */
269 break;
271 *subpath = '/';
274 if (subpath == dirpath)
275 break;
277 subpath--;
280 /* Now subpath should contain the path relative to the fs base */
281 dprintf("subpath = %s\n", subpath);
283 totalbytes = get_size(devfd);
284 get_geometry(devfd, totalbytes, &geo);
286 if (opt.heads)
287 geo.heads = opt.heads;
288 if (opt.sectors)
289 geo.sectors = opt.sectors;
291 /* Patch this into a fake FAT superblock. This isn't because
292 FAT is a good format in any way, it's because it lets the
293 early bootstrap share code with the FAT version. */
294 dprintf("heads = %u, sect = %u\n", geo.heads, geo.sectors);
296 sbs = (struct fat_boot_sector *)syslinux_bootsect;
298 totalsectors = totalbytes >> SECTOR_SHIFT;
299 if (totalsectors >= 65536) {
300 set_16(&sbs->bsSectors, 0);
301 } else {
302 set_16(&sbs->bsSectors, totalsectors);
304 set_32(&sbs->bsHugeSectors, totalsectors);
306 set_16(&sbs->bsBytesPerSec, SECTOR_SIZE);
307 set_16(&sbs->bsSecPerTrack, geo.sectors);
308 set_16(&sbs->bsHeads, geo.heads);
309 set_32(&sbs->bsHiddenSecs, geo.start);
311 /* Construct the boot file map */
313 dprintf("directory inode = %lu\n", (unsigned long)dirst.st_ino);
314 nsect = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
315 nsect += 2; /* Two sectors for the ADV */
316 sectp = alloca(sizeof(sector_t) * nsect);
317 if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS ||
318 fs_type == XFS || fs_type == UFS1 || fs_type == UFS2) {
319 if (sectmap(fd, sectp, nsect)) {
320 perror("bmap");
321 exit(1);
323 } else if (fs_type == BTRFS) {
324 int i;
325 sector_t *sp = sectp;
327 for (i = 0; i < nsect - 2; i++)
328 *sp++ = BTRFS_EXTLINUX_OFFSET/SECTOR_SIZE + i;
329 for (i = 0; i < 2; i++)
330 *sp++ = BTRFS_ADV_OFFSET/SECTOR_SIZE + i;
333 /* Create the modified image in memory */
334 rv = syslinux_patch(sectp, nsect, opt.stupid_mode,
335 opt.raid_mode, subpath, subvol);
337 free(dirpath);
338 return rv;
342 * Install the boot block on the specified device.
343 * Must be run AFTER install_file()!
345 int install_bootblock(int fd, const char *device)
347 struct ext2_super_block sb;
348 struct btrfs_super_block sb2;
349 struct fat_boot_sector sb3;
350 struct ntfs_boot_sector sb4;
351 xfs_sb_t sb5;
352 struct ufs_super_block sb6;
353 bool ok = false;
355 if (fs_type == EXT2) {
356 if (xpread(fd, &sb, sizeof sb, EXT2_SUPER_OFFSET) != sizeof sb) {
357 perror("reading superblock");
358 return 1;
361 if (sb.s_magic == EXT2_SUPER_MAGIC)
362 ok = true;
363 } else if (fs_type == BTRFS) {
364 if (xpread(fd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET)
365 != sizeof sb2) {
366 perror("reading superblock");
367 return 1;
369 if (!memcmp(sb2.magic, BTRFS_MAGIC, BTRFS_MAGIC_L))
370 ok = true;
371 } else if (fs_type == VFAT) {
372 if (xpread(fd, &sb3, sizeof sb3, 0) != sizeof sb3) {
373 perror("reading fat superblock");
374 return 1;
377 if (fat_check_sb_fields(&sb3))
378 ok = true;
379 } else if (fs_type == NTFS) {
380 if (xpread(fd, &sb4, sizeof(sb4), 0) != sizeof(sb4)) {
381 perror("reading ntfs superblock");
382 return 1;
385 if (ntfs_check_sb_fields(&sb4))
386 ok = true;
387 } else if (fs_type == XFS) {
388 if (xpread(fd, &sb5, sizeof sb5, 0) != sizeof sb5) {
389 perror("reading xfs superblock");
390 return 1;
393 if (sb5.sb_magicnum == *(u32 *)XFS_SB_MAGIC) {
394 if (be32_to_cpu(sb5.sb_blocksize) != XFS_SUPPORTED_BLOCKSIZE) {
395 fprintf(stderr,
396 "You need to have 4 KiB filesystem block size for "
397 " being able to install Syslinux in your XFS "
398 "partition (because there is no enough space in MBR to "
399 "determine where Syslinux bootsector can be installed "
400 "regardless the filesystem block size)\n");
401 return 1;
404 ok = true;
406 } else if (fs_type == UFS1 || fs_type == UFS2) {
407 uint32_t sblock_off = (fs_type == UFS1) ?
408 SBLOCK_UFS1 : SBLOCK_UFS2;
409 uint32_t ufs_smagic = (fs_type == UFS1) ?
410 UFS1_SUPER_MAGIC : UFS2_SUPER_MAGIC;
412 if (xpread(fd, &sb6, sizeof sb6, sblock_off) != sizeof sb6) {
413 perror("reading superblock");
414 return 1;
417 if (sb6.fs_magic == ufs_smagic)
418 ok = true;
421 if (!ok) {
422 fprintf(stderr,
423 "no fat, ntfs, ext2/3/4, btrfs, xfs "
424 "or ufs1/2 superblock found on %s\n",
425 device);
426 return 1;
429 if (fs_type == VFAT) {
430 struct fat_boot_sector *sbs = (struct fat_boot_sector *)syslinux_bootsect;
431 if (xpwrite(fd, &sbs->FAT_bsHead, FAT_bsHeadLen, 0) != FAT_bsHeadLen ||
432 xpwrite(fd, &sbs->FAT_bsCode, FAT_bsCodeLen,
433 offsetof(struct fat_boot_sector, FAT_bsCode)) != FAT_bsCodeLen) {
434 perror("writing fat bootblock");
435 return 1;
437 } else if (fs_type == NTFS) {
438 struct ntfs_boot_sector *sbs =
439 (struct ntfs_boot_sector *)syslinux_bootsect;
440 if (xpwrite(fd, &sbs->NTFS_bsHead,
441 NTFS_bsHeadLen, 0) != NTFS_bsHeadLen ||
442 xpwrite(fd, &sbs->NTFS_bsCode, NTFS_bsCodeLen,
443 offsetof(struct ntfs_boot_sector,
444 NTFS_bsCode)) != NTFS_bsCodeLen) {
445 perror("writing ntfs bootblock");
446 return 1;
448 } else if (fs_type == XFS) {
449 if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len,
450 XFS_BOOTSECT_OFFSET) != syslinux_bootsect_len) {
451 perror("writing xfs bootblock");
452 return 1;
454 } else {
455 if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len, 0)
456 != syslinux_bootsect_len) {
457 perror("writing bootblock");
458 return 1;
462 return 0;
465 static int rewrite_boot_image(int devfd, const char *path, const char *filename)
467 int fd;
468 int ret;
469 int modbytes;
471 /* Let's create LDLINUX.SYS file again (if it already exists, of course) */
472 fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
473 S_IRUSR | S_IRGRP | S_IROTH);
474 if (fd < 0) {
475 perror(filename);
476 return -1;
479 /* Write boot image data into LDLINUX.SYS file */
480 ret = xpwrite(fd, (const char _force *)boot_image, boot_image_len, 0);
481 if (ret != boot_image_len) {
482 perror("writing bootblock");
483 goto error;
486 /* Write ADV */
487 ret = xpwrite(fd, syslinux_adv, 2 * ADV_SIZE, boot_image_len);
488 if (ret != 2 * ADV_SIZE) {
489 fprintf(stderr, "%s: write failure on %s\n", program, filename);
490 goto error;
493 /* Map the file, and patch the initial sector accordingly */
494 modbytes = patch_file_and_bootblock(fd, path, devfd);
496 /* Write the patch area again - this relies on the file being overwritten
497 * in place! */
498 ret = xpwrite(fd, (const char _force *)boot_image, modbytes, 0);
499 if (ret != modbytes) {
500 fprintf(stderr, "%s: write failure on %s\n", program, filename);
501 goto error;
504 return fd;
506 error:
507 close(fd);
509 return -1;
512 int ext2_fat_install_file(const char *path, int devfd, struct stat *rst)
514 char *file, *oldfile, *c32file;
515 int fd = -1, dirfd = -1;
516 int r1, r2, r3;
518 r1 = asprintf(&file, "%s%sldlinux.sys",
519 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
520 r2 = asprintf(&oldfile, "%s%sextlinux.sys",
521 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
522 r3 = asprintf(&c32file, "%s%sldlinux.c32",
523 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
524 if (r1 < 0 || !file || r2 < 0 || !oldfile || r3 < 0 || !c32file) {
525 perror(program);
526 return 1;
529 dirfd = open(path, O_RDONLY | O_DIRECTORY);
530 if (dirfd < 0) {
531 perror(path);
532 goto bail;
535 fd = open(file, O_RDONLY);
536 if (fd < 0) {
537 if (errno != ENOENT) {
538 perror(file);
539 goto bail;
541 } else {
542 clear_attributes(fd);
544 close(fd);
546 fd = rewrite_boot_image(devfd, path, file);
547 if (fd < 0)
548 goto bail;
550 /* Attempt to set immutable flag and remove all write access */
551 /* Only set immutable flag if file is owned by root */
552 set_attributes(fd);
554 if (fstat(fd, rst)) {
555 perror(file);
556 goto bail;
559 close(dirfd);
560 close(fd);
562 /* Look if we have the old filename */
563 fd = open(oldfile, O_RDONLY);
564 if (fd >= 0) {
565 clear_attributes(fd);
566 close(fd);
567 unlink(oldfile);
570 fd = open(c32file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
571 S_IRUSR | S_IRGRP | S_IROTH);
572 if (fd < 0) {
573 perror(c32file);
574 goto bail;
577 r3 = xpwrite(fd, (const char _force *)syslinux_ldlinuxc32,
578 syslinux_ldlinuxc32_len, 0);
579 if (r3 != syslinux_ldlinuxc32_len) {
580 fprintf(stderr, "%s: write failure on %s\n", program, c32file);
581 goto bail;
584 free(file);
585 free(oldfile);
586 free(c32file);
587 return 0;
589 bail:
590 if (dirfd >= 0)
591 close(dirfd);
592 if (fd >= 0)
593 close(fd);
595 free(file);
596 free(oldfile);
597 free(c32file);
598 return 1;
601 /* btrfs has to install ldlinux.sys to a boot area, which is not managed by
602 btrfs tree, so actually this is not installed as a file, since the cow
603 feature of btrfs would move the ldlinux.sys file everywhere. Older
604 versions installed it to the first 64kiB (aka Boot Area A) but as of
605 commit ID 37eef640 (before 6.03-pre12, before 6.03), it is now in Boot
606 Area B (a 768kiB blank space at offset 256kiB). */
607 int btrfs_install_file(const char *path, int devfd, struct stat *rst)
609 char *file;
610 int fd, rv;
612 patch_file_and_bootblock(-1, path, devfd);
613 if (xpwrite(devfd, (const char _force *)boot_image,
614 boot_image_len, BTRFS_EXTLINUX_OFFSET)
615 != boot_image_len) {
616 perror("writing bootblock");
617 return 1;
619 dprintf("write boot_image to 0x%x\n", BTRFS_EXTLINUX_OFFSET);
620 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET)
621 != 2 * ADV_SIZE) {
622 perror("writing adv");
623 return 1;
625 dprintf("write adv to 0x%x\n", BTRFS_ADV_OFFSET);
626 if (stat(path, rst)) {
627 perror(path);
628 return 1;
632 * Note that we *can* install ldinux.c32 as a regular file because
633 * it doesn't need to be within the first 64K. The Syslinux core
634 * has enough smarts to search the btrfs dirs and find this file.
636 rv = asprintf(&file, "%s%sldlinux.c32",
637 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
638 if (rv < 0 || !file) {
639 perror(program);
640 return 1;
643 fd = open(file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
644 S_IRUSR | S_IRGRP | S_IROTH);
645 if (fd < 0) {
646 perror(file);
647 free(file);
648 return 1;
651 rv = xpwrite(fd, (const char _force *)syslinux_ldlinuxc32,
652 syslinux_ldlinuxc32_len, 0);
653 if (rv != (int)syslinux_ldlinuxc32_len) {
654 fprintf(stderr, "%s: write failure on %s\n", program, file);
655 rv = 1;
656 } else
657 rv = 0;
659 close(fd);
660 free(file);
661 return rv;
665 * Due to historical reasons (SGI IRIX's design of disk layouts), the first
666 * sector in the primary AG on XFS filesystems contains the superblock, which is
667 * a problem with bootloaders that rely on BIOSes (that load VBRs which are
668 * located in the first sector of the partition).
670 * Thus, we need to handle this issue, otherwise Syslinux will damage the XFS's
671 * superblock.
673 static int xfs_install_file(const char *path, int devfd, struct stat *rst)
675 static char file[PATH_MAX + 1];
676 static char c32file[PATH_MAX + 1];
677 int dirfd = -1;
678 int fd = -1;
679 int retval;
681 snprintf(file, PATH_MAX + 1, "%s%sldlinux.sys", path,
682 path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
683 snprintf(c32file, PATH_MAX + 1, "%s%sldlinux.c32", path,
684 path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
686 dirfd = open(path, O_RDONLY | O_DIRECTORY);
687 if (dirfd < 0) {
688 perror(path);
689 goto bail;
692 fd = open(file, O_RDONLY);
693 if (fd < 0) {
694 if (errno != ENOENT) {
695 perror(file);
696 goto bail;
698 } else {
699 clear_attributes(fd);
702 close(fd);
704 fd = rewrite_boot_image(devfd, path, file);
705 if (fd < 0)
706 goto bail;
708 /* Attempt to set immutable flag and remove all write access */
709 /* Only set immutable flag if file is owned by root */
710 set_attributes(fd);
712 if (fstat(fd, rst)) {
713 perror(file);
714 goto bail;
717 close(dirfd);
718 close(fd);
720 dirfd = -1;
721 fd = -1;
723 fd = open(c32file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
724 S_IRUSR | S_IRGRP | S_IROTH);
725 if (fd < 0) {
726 perror(c32file);
727 goto bail;
730 retval = xpwrite(fd, (const char _force *)syslinux_ldlinuxc32,
731 syslinux_ldlinuxc32_len, 0);
732 if (retval != (int)syslinux_ldlinuxc32_len) {
733 fprintf(stderr, "%s: write failure on %s\n", program, file);
734 goto bail;
737 close(fd);
739 sync();
741 return 0;
743 bail:
744 if (dirfd >= 0)
745 close(dirfd);
747 if (fd >= 0)
748 close(fd);
750 return 1;
754 * * test if path is a subvolume:
755 * * this function return
756 * * 0-> path exists but it is not a subvolume
757 * * 1-> path exists and it is a subvolume
758 * * -1 -> path is unaccessible
759 * */
760 static int test_issubvolume(char *path)
763 struct stat st;
764 int res;
766 res = stat(path, &st);
767 if(res < 0 )
768 return -1;
770 return (st.st_ino == 256) && S_ISDIR(st.st_mode);
775 * Get the default subvolume of a btrfs filesystem
776 * rootdir: btrfs root dir
777 * subvol: this function will save the default subvolume name here
779 static char * get_default_subvol(char * rootdir, char * subvol)
781 struct btrfs_ioctl_search_args args;
782 struct btrfs_ioctl_search_key *sk = &args.key;
783 struct btrfs_ioctl_search_header *sh;
784 int ret, i;
785 int fd;
786 struct btrfs_root_ref *ref;
787 struct btrfs_dir_item *dir_item;
788 unsigned long off = 0;
789 int name_len;
790 char *name;
791 char dirname[4096];
792 u64 defaultsubvolid = 0;
794 ret = test_issubvolume(rootdir);
795 if (ret == 1) {
796 fd = open(rootdir, O_RDONLY);
797 if (fd < 0) {
798 fprintf(stderr, "ERROR: failed to open %s\n", rootdir);
800 ret = fd;
802 if (ret <= 0) {
803 subvol[0] = '\0';
804 return NULL;
807 memset(&args, 0, sizeof(args));
809 /* search in the tree of tree roots */
810 sk->tree_id = 1;
813 * set the min and max to backref keys. The search will
814 * only send back this type of key now.
816 sk->max_type = BTRFS_DIR_ITEM_KEY;
817 sk->min_type = BTRFS_DIR_ITEM_KEY;
820 * set all the other params to the max, we'll take any objectid
821 * and any trans
823 sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
824 sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
826 sk->max_offset = (u64)-1;
827 sk->min_offset = 0;
828 sk->max_transid = (u64)-1;
830 /* just a big number, doesn't matter much */
831 sk->nr_items = 4096;
833 while(1) {
834 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
835 if (ret < 0) {
836 fprintf(stderr, "ERROR: can't perform the search\n");
837 subvol[0] = '\0';
838 return NULL;
840 /* the ioctl returns the number of item it found in nr_items */
841 if (sk->nr_items == 0) {
842 break;
845 off = 0;
848 * for each item, pull the key out of the header and then
849 * read the root_ref item it contains
851 for (i = 0; i < sk->nr_items; i++) {
852 sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
853 off += sizeof(*sh);
854 if (sh->type == BTRFS_DIR_ITEM_KEY) {
855 dir_item = (struct btrfs_dir_item *)(args.buf + off);
856 name_len = dir_item->name_len;
857 name = (char *)(dir_item + 1);
860 /*add_root(&root_lookup, sh->objectid, sh->offset,
861 dir_id, name, name_len);*/
862 strncpy(dirname, name, name_len);
863 dirname[name_len] = '\0';
864 if (strcmp(dirname, "default") == 0) {
865 defaultsubvolid = dir_item->location.objectid;
866 break;
869 off += sh->len;
872 * record the mins in sk so we can make sure the
873 * next search doesn't repeat this root
875 sk->min_objectid = sh->objectid;
876 sk->min_type = sh->type;
877 sk->max_type = sh->type;
878 sk->min_offset = sh->offset;
880 if (defaultsubvolid != 0)
881 break;
882 sk->nr_items = 4096;
883 /* this iteration is done, step forward one root for the next
884 * ioctl
886 if (sk->min_objectid < (u64)-1) {
887 sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
888 sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
889 sk->max_type = BTRFS_ROOT_BACKREF_KEY;
890 sk->min_type = BTRFS_ROOT_BACKREF_KEY;
891 sk->min_offset = 0;
892 } else
893 break;
896 if (defaultsubvolid == 0) {
897 subvol[0] = '\0';
898 return NULL;
901 memset(&args, 0, sizeof(args));
903 /* search in the tree of tree roots */
904 sk->tree_id = 1;
907 * set the min and max to backref keys. The search will
908 * only send back this type of key now.
910 sk->max_type = BTRFS_ROOT_BACKREF_KEY;
911 sk->min_type = BTRFS_ROOT_BACKREF_KEY;
914 * set all the other params to the max, we'll take any objectid
915 * and any trans
917 sk->max_objectid = (u64)-1;
918 sk->max_offset = (u64)-1;
919 sk->max_transid = (u64)-1;
921 /* just a big number, doesn't matter much */
922 sk->nr_items = 4096;
924 while(1) {
925 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
926 if (ret < 0) {
927 fprintf(stderr, "ERROR: can't perform the search\n");
928 subvol[0] = '\0';
929 return NULL;
931 /* the ioctl returns the number of item it found in nr_items */
932 if (sk->nr_items == 0)
933 break;
935 off = 0;
938 * for each item, pull the key out of the header and then
939 * read the root_ref item it contains
941 for (i = 0; i < sk->nr_items; i++) {
942 sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
943 off += sizeof(*sh);
944 if (sh->type == BTRFS_ROOT_BACKREF_KEY) {
945 ref = (struct btrfs_root_ref *)(args.buf + off);
946 name_len = ref->name_len;
947 name = (char *)(ref + 1);
949 if (sh->objectid == defaultsubvolid) {
950 strncpy(subvol, name, name_len);
951 subvol[name_len] = '\0';
952 dprintf("The default subvolume: %s, ID: %llu\n",
953 subvol, sh->objectid);
954 break;
959 off += sh->len;
962 * record the mins in sk so we can make sure the
963 * next search doesn't repeat this root
965 sk->min_objectid = sh->objectid;
966 sk->min_type = sh->type;
967 sk->min_offset = sh->offset;
969 if (subvol[0] != '\0')
970 break;
971 sk->nr_items = 4096;
972 /* this iteration is done, step forward one root for the next
973 * ioctl
975 if (sk->min_objectid < (u64)-1) {
976 sk->min_objectid++;
977 sk->min_type = BTRFS_ROOT_BACKREF_KEY;
978 sk->min_offset = 0;
979 } else
980 break;
982 return subvol;
985 static int install_file(const char *path, int devfd, struct stat *rst)
987 if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS
988 || fs_type == UFS1 || fs_type == UFS2)
989 return ext2_fat_install_file(path, devfd, rst);
990 else if (fs_type == BTRFS)
991 return btrfs_install_file(path, devfd, rst);
992 else if (fs_type == XFS)
993 return xfs_install_file(path, devfd, rst);
995 return 1;
998 #ifdef __KLIBC__
999 static char devname_buf[64];
1001 static void device_cleanup(void)
1003 unlink(devname_buf);
1005 #endif
1007 /* Verify that a device fd and a pathname agree.
1008 Return 0 on valid, -1 on error. */
1009 static int validate_device_btrfs(int pathfd, int devfd);
1010 static int validate_device(const char *path, int devfd)
1012 struct stat pst, dst;
1013 struct statfs sfs;
1014 int pfd;
1015 int rv = -1;
1017 pfd = open(path, O_RDONLY|O_DIRECTORY);
1018 if (pfd < 0)
1019 goto err;
1021 if (fstat(pfd, &pst) || fstat(devfd, &dst) || statfs(path, &sfs))
1022 goto err;
1024 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
1025 if (fs_type == BTRFS) {
1026 if (sfs.f_type == BTRFS_SUPER_MAGIC)
1027 rv = validate_device_btrfs(pfd, devfd);
1028 } else {
1029 rv = (pst.st_dev == dst.st_rdev) ? 0 : -1;
1032 err:
1033 if (pfd >= 0)
1034 close(pfd);
1035 return rv;
1038 #ifndef __KLIBC__
1039 static char *find_device(const char *mtab_file, dev_t dev)
1041 struct mntent *mnt;
1042 struct stat dst;
1043 FILE *mtab;
1044 char *devname = NULL;
1045 bool done;
1047 mtab = setmntent(mtab_file, "r");
1048 if (!mtab)
1049 return NULL;
1051 done = false;
1052 while ((mnt = getmntent(mtab))) {
1053 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
1054 switch (fs_type) {
1055 case BTRFS:
1056 if (!strcmp(mnt->mnt_type, "btrfs") &&
1057 !stat(mnt->mnt_dir, &dst) &&
1058 dst.st_dev == dev) {
1059 if (!subvol[0])
1060 get_default_subvol(mnt->mnt_dir, subvol);
1061 done = true;
1063 break;
1064 case EXT2:
1065 if ((!strcmp(mnt->mnt_type, "ext2") ||
1066 !strcmp(mnt->mnt_type, "ext3") ||
1067 !strcmp(mnt->mnt_type, "ext4")) &&
1068 !stat(mnt->mnt_fsname, &dst) &&
1069 dst.st_rdev == dev) {
1070 done = true;
1071 break;
1073 case VFAT:
1074 if ((!strcmp(mnt->mnt_type, "vfat")) &&
1075 !stat(mnt->mnt_fsname, &dst) &&
1076 dst.st_rdev == dev) {
1077 done = true;
1078 break;
1080 case NTFS:
1081 if ((!strcmp(mnt->mnt_type, "fuseblk") /* ntfs-3g */ ||
1082 !strcmp(mnt->mnt_type, "ntfs")) &&
1083 !stat(mnt->mnt_fsname, &dst) &&
1084 dst.st_rdev == dev) {
1085 done = true;
1086 break;
1089 break;
1090 case XFS:
1091 if (!strcmp(mnt->mnt_type, "xfs") && !stat(mnt->mnt_fsname, &dst) &&
1092 dst.st_rdev == dev) {
1093 done = true;
1094 break;
1097 break;
1098 case UFS1:
1099 case UFS2:
1100 if (!strcmp(mnt->mnt_type, "ufs") && !stat(mnt->mnt_fsname, &dst) &&
1101 dst.st_rdev == dev) {
1102 done = true;
1105 break;
1106 case NONE:
1107 break;
1110 if (done) {
1111 devname = strdup(mnt->mnt_fsname);
1112 break;
1116 endmntent(mtab);
1118 return devname;
1120 #endif
1123 * On newer Linux kernels we can use sysfs to get a backwards mapping
1124 * from device names to standard filenames
1126 static char *find_device_sysfs(dev_t dev)
1128 char sysname[64];
1129 char linkname[PATH_MAX];
1130 ssize_t llen;
1131 char *p, *q;
1132 char *buf = NULL;
1133 struct stat st;
1135 snprintf(sysname, sizeof sysname, "/sys/dev/block/%u:%u",
1136 major(dev), minor(dev));
1138 llen = readlink(sysname, linkname, sizeof linkname);
1139 if (llen < 0 || llen >= sizeof linkname)
1140 goto err;
1142 linkname[llen] = '\0';
1144 p = strrchr(linkname, '/');
1145 p = p ? p+1 : linkname; /* Leave basename */
1147 buf = q = malloc(strlen(p) + 6);
1148 if (!buf)
1149 goto err;
1151 memcpy(q, "/dev/", 5);
1152 q += 5;
1154 while (*p) {
1155 *q++ = (*p == '!') ? '/' : *p;
1156 p++;
1159 *q = '\0';
1161 if (!stat(buf, &st) && st.st_dev == dev)
1162 return buf; /* Found it! */
1164 err:
1165 if (buf)
1166 free(buf);
1167 return NULL;
1170 static const char *find_device_mountinfo(const char *path, dev_t dev)
1172 const struct mountinfo *m;
1173 struct stat st;
1175 m = find_mount(path, NULL);
1176 if (!m)
1177 return NULL;
1179 if (m->devpath[0] == '/' && m->dev == dev &&
1180 !stat(m->devpath, &st) && S_ISBLK(st.st_mode) && st.st_rdev == dev)
1181 return m->devpath;
1182 else
1183 return NULL;
1186 static int validate_device_btrfs(int pfd, int dfd)
1188 struct btrfs_ioctl_fs_info_args fsinfo;
1189 static struct btrfs_ioctl_dev_info_args devinfo;
1190 struct btrfs_super_block sb2;
1192 if (ioctl(pfd, BTRFS_IOC_FS_INFO, &fsinfo))
1193 return -1;
1195 /* We do not support multi-device btrfs yet */
1196 if (fsinfo.num_devices != 1)
1197 return -1;
1199 /* The one device will have the max devid */
1200 memset(&devinfo, 0, sizeof devinfo);
1201 devinfo.devid = fsinfo.max_id;
1202 if (ioctl(pfd, BTRFS_IOC_DEV_INFO, &devinfo))
1203 return -1;
1205 if (devinfo.path[0] != '/')
1206 return -1;
1208 if (xpread(dfd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET) != sizeof sb2)
1209 return -1;
1211 if (memcmp(sb2.magic, BTRFS_MAGIC, BTRFS_MAGIC_L))
1212 return -1;
1214 if (memcmp(sb2.fsid, fsinfo.fsid, sizeof fsinfo.fsid))
1215 return -1;
1217 if (sb2.num_devices != 1)
1218 return -1;
1220 if (sb2.dev_item.devid != devinfo.devid)
1221 return -1;
1223 if (memcmp(sb2.dev_item.uuid, devinfo.uuid, sizeof devinfo.uuid))
1224 return -1;
1226 if (memcmp(sb2.dev_item.fsid, fsinfo.fsid, sizeof fsinfo.fsid))
1227 return -1;
1229 return 0; /* It's good! */
1232 static const char *find_device_btrfs(const char *path)
1234 int pfd, dfd;
1235 struct btrfs_ioctl_fs_info_args fsinfo;
1236 static struct btrfs_ioctl_dev_info_args devinfo;
1237 const char *rv = NULL;
1239 pfd = dfd = -1;
1241 pfd = open(path, O_RDONLY);
1242 if (pfd < 0)
1243 goto err;
1245 if (ioctl(pfd, BTRFS_IOC_FS_INFO, &fsinfo))
1246 goto err;
1248 /* We do not support multi-device btrfs yet */
1249 if (fsinfo.num_devices != 1)
1250 goto err;
1252 /* The one device will have the max devid */
1253 memset(&devinfo, 0, sizeof devinfo);
1254 devinfo.devid = fsinfo.max_id;
1255 if (ioctl(pfd, BTRFS_IOC_DEV_INFO, &devinfo))
1256 goto err;
1258 if (devinfo.path[0] != '/')
1259 goto err;
1261 dfd = open((const char *)devinfo.path, O_RDONLY);
1262 if (dfd < 0)
1263 goto err;
1265 if (!validate_device_btrfs(pfd, dfd))
1266 rv = (const char *)devinfo.path; /* It's good! */
1268 err:
1269 if (pfd >= 0)
1270 close(pfd);
1271 if (dfd >= 0)
1272 close(dfd);
1273 return rv;
1276 static char *dupname(const char *name)
1278 char *out = NULL;
1279 int len = 0;
1280 if (name)
1281 len = strlen(name);
1282 if (len > 0)
1283 out = strndup(name, len);
1284 return out;
1287 static char *get_devname(const char *path)
1289 char *devname = NULL;
1290 struct stat st;
1291 struct statfs sfs;
1293 if (stat(path, &st) || !S_ISDIR(st.st_mode)) {
1294 fprintf(stderr, "%s: Not a directory: %s\n", program, path);
1295 return devname;
1297 if (statfs(path, &sfs)) {
1298 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
1299 return devname;
1302 if (opt.device)
1303 devname = strdup(opt.device);
1305 if (!devname){
1306 if (fs_type == BTRFS) {
1307 /* For btrfs try to get the device name from btrfs itself */
1308 devname = dupname(find_device_btrfs(path));
1312 if (!devname) {
1313 devname = dupname(find_device_mountinfo(path, st.st_dev));
1316 #ifdef __KLIBC__
1317 if (!devname) {
1318 devname = find_device_sysfs(st.st_dev);
1320 if (!devname) {
1321 /* klibc doesn't have getmntent and friends; instead, just create
1322 a new device with the appropriate device type */
1323 snprintf(devname_buf, sizeof devname_buf, "/tmp/dev-%u:%u",
1324 major(st.st_dev), minor(st.st_dev));
1326 if (mknod(devname_buf, S_IFBLK | 0600, st.st_dev)) {
1327 fprintf(stderr, "%s: cannot create device %s\n", program, devname);
1328 return devname;
1331 atexit(device_cleanup); /* unlink the device node on exit */
1332 devname = dupname(devname_buf);
1335 #else
1336 if (!devname) {
1337 devname = find_device("/proc/mounts", st.st_dev);
1339 if (!devname) {
1340 /* Didn't find it in /proc/mounts, try /etc/mtab */
1341 devname = find_device("/etc/mtab", st.st_dev);
1343 if (!devname) {
1344 devname = find_device_sysfs(st.st_dev);
1346 fprintf(stderr, "%s: cannot find device for path %s\n", program, path);
1347 return devname;
1350 fprintf(stderr, "%s is device %s\n", path, devname);
1352 #endif
1353 return devname;
1356 static int open_device(const char *path, struct stat *st, char **_devname)
1358 int devfd;
1359 char *devname = NULL;
1360 struct statfs sfs;
1362 if (st)
1363 if (stat(path, st) || !S_ISDIR(st->st_mode)) {
1364 fprintf(stderr, "%s: Not a directory: %s\n", program, path);
1365 return -1;
1368 if (statfs(path, &sfs)) {
1369 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
1370 return -1;
1373 if (sfs.f_type == EXT2_SUPER_MAGIC)
1374 fs_type = EXT2;
1375 else if (sfs.f_type == BTRFS_SUPER_MAGIC)
1376 fs_type = BTRFS;
1377 else if (sfs.f_type == MSDOS_SUPER_MAGIC)
1378 fs_type = VFAT;
1379 else if (sfs.f_type == NTFS_SB_MAGIC ||
1380 sfs.f_type == FUSE_SUPER_MAGIC /* ntfs-3g */)
1381 fs_type = NTFS;
1382 else if (sfs.f_type == XFS_SUPER_MAGIC)
1383 fs_type = XFS;
1384 else if (sfs.f_type == UFS1_SUPER_MAGIC)
1385 fs_type = UFS1;
1386 else if (sfs.f_type == UFS2_SUPER_MAGIC)
1387 fs_type = UFS2;
1389 if (!fs_type) {
1390 fprintf(stderr,
1391 "%s: not a fat, ntfs, ext2/3/4, btrfs, xfs or"
1392 "ufs1/2 filesystem: %s\n",
1393 program, path);
1394 return -1;
1397 devfd = -1;
1398 devname = get_devname(path);
1400 if ((devfd = open(devname, O_RDWR | O_SYNC)) < 0) {
1401 fprintf(stderr, "%s: cannot open device %s\n", program, devname);
1402 free(devname);
1403 return -1;
1406 /* Verify that the device we opened is the device intended */
1407 if (validate_device(path, devfd)) {
1408 fprintf(stderr, "%s: path %s doesn't match device %s\n",
1409 program, path, devname);
1410 free(devname);
1411 close(devfd);
1412 return -1;
1414 if (_devname)
1415 *_devname = devname;
1416 else
1417 free(devname);
1418 return devfd;
1421 static int btrfs_read_adv(int devfd)
1423 if (xpread(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET)
1424 != 2 * ADV_SIZE)
1425 return -1;
1427 return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
1430 static inline int xfs_read_adv(int devfd)
1432 const size_t adv_size = 2 * ADV_SIZE;
1434 if (xpread(devfd, syslinux_adv, adv_size, boot_image_len) != adv_size)
1435 return -1;
1437 return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
1440 static int ext_read_adv(const char *path, int devfd, const char **namep)
1442 int err;
1443 const char *name;
1445 if (fs_type == BTRFS) {
1446 /* btrfs "ldlinux.sys" is in 64k blank area */
1447 return btrfs_read_adv(devfd);
1448 } else if (fs_type == XFS) {
1449 /* XFS "ldlinux.sys" is in the first 2048 bytes of the primary AG */
1450 return xfs_read_adv(devfd);
1451 } else {
1452 err = read_adv(path, name = "ldlinux.sys");
1453 if (err == 2) /* ldlinux.sys does not exist */
1454 err = read_adv(path, name = "extlinux.sys");
1455 if (namep)
1456 *namep = name;
1457 return err;
1461 static int ext_write_adv(const char *path, const char *cfg, int devfd)
1463 if (fs_type == BTRFS) { /* btrfs "ldlinux.sys" is in 64k blank area */
1464 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE,
1465 BTRFS_ADV_OFFSET) != 2 * ADV_SIZE) {
1466 perror("writing adv");
1467 return 1;
1469 return 0;
1471 return write_adv(path, cfg);
1474 static int install_loader(const char *path, int update_only)
1476 struct stat st, fst;
1477 int devfd, rv;
1478 char *devname = NULL;
1480 devfd = open_device(path, &st, &devname);
1481 if (devfd < 0)
1482 return 1;
1484 if (update_only && !syslinux_already_installed(devfd)) {
1485 fprintf(stderr, "%s: no previous syslinux boot sector found\n",
1486 program);
1487 close(devfd);
1488 return 1;
1491 /* Read a pre-existing ADV, if already installed */
1492 if (opt.reset_adv) {
1493 syslinux_reset_adv(syslinux_adv);
1494 } else if (ext_read_adv(path, devfd, NULL) < 0) {
1495 close(devfd);
1496 return 1;
1499 if (modify_adv() < 0) {
1500 close(devfd);
1501 return 1;
1504 /* Install ldlinux.sys */
1505 if (install_file(path, devfd, &fst)) {
1506 close(devfd);
1507 return 1;
1509 if (fst.st_dev != st.st_dev) {
1510 fprintf(stderr, "%s: file system changed under us - aborting!\n",
1511 program);
1512 close(devfd);
1513 return 1;
1516 sync();
1517 rv = install_bootblock(devfd, devname);
1518 free(devname);
1519 close(devfd);
1520 sync();
1522 return rv;
1526 * Modify the ADV of an existing installation
1528 int modify_existing_adv(const char *path)
1530 const char *filename;
1531 int devfd;
1533 devfd = open_device(path, NULL, NULL);
1534 if (devfd < 0)
1535 return 1;
1537 if (ext_read_adv(path, devfd, &filename) < 0) {
1538 close(devfd);
1539 return 1;
1541 if (modify_adv() < 0) {
1542 close(devfd);
1543 return 1;
1545 if (ext_write_adv(path, filename, devfd) < 0) {
1546 close(devfd);
1547 return 1;
1549 close(devfd);
1550 return 0;
1553 int main(int argc, char *argv[])
1555 parse_options(argc, argv, MODE_EXTLINUX);
1557 if (!opt.directory || opt.install_mbr || opt.activate_partition)
1558 usage(EX_USAGE, 0);
1560 if (opt.update_only == -1) {
1561 if (opt.reset_adv || opt.set_once || opt.menu_save)
1562 return modify_existing_adv(opt.directory);
1563 else
1564 usage(EX_USAGE, MODE_EXTLINUX);
1567 return install_loader(opt.directory, opt.update_only);