extlinux/main.c: comment typo fixes
[syslinux.git] / extlinux / main.c
blob26eb43c74f9ac475d6a4b76a70fe093a64a55a48
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 in the first 64K blank area, which
602 is not managed by btrfs tree, so actually this is not installed as a file,
603 since the cow feature of btrfs would move the ldlinux.sys file everywhere. */
604 int btrfs_install_file(const char *path, int devfd, struct stat *rst)
606 char *file;
607 int fd, rv;
609 patch_file_and_bootblock(-1, path, devfd);
610 if (xpwrite(devfd, (const char _force *)boot_image,
611 boot_image_len, BTRFS_EXTLINUX_OFFSET)
612 != boot_image_len) {
613 perror("writing bootblock");
614 return 1;
616 dprintf("write boot_image to 0x%x\n", BTRFS_EXTLINUX_OFFSET);
617 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET)
618 != 2 * ADV_SIZE) {
619 perror("writing adv");
620 return 1;
622 dprintf("write adv to 0x%x\n", BTRFS_ADV_OFFSET);
623 if (stat(path, rst)) {
624 perror(path);
625 return 1;
629 * Note that we *can* install ldinux.c32 as a regular file because
630 * it doesn't need to be within the first 64K. The Syslinux core
631 * has enough smarts to search the btrfs dirs and find this file.
633 rv = asprintf(&file, "%s%sldlinux.c32",
634 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
635 if (rv < 0 || !file) {
636 perror(program);
637 return 1;
640 fd = open(file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
641 S_IRUSR | S_IRGRP | S_IROTH);
642 if (fd < 0) {
643 perror(file);
644 free(file);
645 return 1;
648 rv = xpwrite(fd, (const char _force *)syslinux_ldlinuxc32,
649 syslinux_ldlinuxc32_len, 0);
650 if (rv != (int)syslinux_ldlinuxc32_len) {
651 fprintf(stderr, "%s: write failure on %s\n", program, file);
652 rv = 1;
653 } else
654 rv = 0;
656 close(fd);
657 free(file);
658 return rv;
662 * Due to historical reasons (SGI IRIX's design of disk layouts), the first
663 * sector in the primary AG on XFS filesystems contains the superblock, which is
664 * a problem with bootloaders that rely on BIOSes (that load VBRs which are
665 * located in the first sector of the partition).
667 * Thus, we need to handle this issue, otherwise Syslinux will damage the XFS's
668 * superblock.
670 static int xfs_install_file(const char *path, int devfd, struct stat *rst)
672 static char file[PATH_MAX + 1];
673 static char c32file[PATH_MAX + 1];
674 int dirfd = -1;
675 int fd = -1;
676 int retval;
678 snprintf(file, PATH_MAX + 1, "%s%sldlinux.sys", path,
679 path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
680 snprintf(c32file, PATH_MAX + 1, "%s%sldlinux.c32", path,
681 path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
683 dirfd = open(path, O_RDONLY | O_DIRECTORY);
684 if (dirfd < 0) {
685 perror(path);
686 goto bail;
689 fd = open(file, O_RDONLY);
690 if (fd < 0) {
691 if (errno != ENOENT) {
692 perror(file);
693 goto bail;
695 } else {
696 clear_attributes(fd);
699 close(fd);
701 fd = rewrite_boot_image(devfd, path, file);
702 if (fd < 0)
703 goto bail;
705 /* Attempt to set immutable flag and remove all write access */
706 /* Only set immutable flag if file is owned by root */
707 set_attributes(fd);
709 if (fstat(fd, rst)) {
710 perror(file);
711 goto bail;
714 close(dirfd);
715 close(fd);
717 dirfd = -1;
718 fd = -1;
720 fd = open(c32file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
721 S_IRUSR | S_IRGRP | S_IROTH);
722 if (fd < 0) {
723 perror(c32file);
724 goto bail;
727 retval = xpwrite(fd, (const char _force *)syslinux_ldlinuxc32,
728 syslinux_ldlinuxc32_len, 0);
729 if (retval != (int)syslinux_ldlinuxc32_len) {
730 fprintf(stderr, "%s: write failure on %s\n", program, file);
731 goto bail;
734 close(fd);
736 sync();
738 return 0;
740 bail:
741 if (dirfd >= 0)
742 close(dirfd);
744 if (fd >= 0)
745 close(fd);
747 return 1;
751 * * test if path is a subvolume:
752 * * this function return
753 * * 0-> path exists but it is not a subvolume
754 * * 1-> path exists and it is a subvolume
755 * * -1 -> path is unaccessible
756 * */
757 static int test_issubvolume(char *path)
760 struct stat st;
761 int res;
763 res = stat(path, &st);
764 if(res < 0 )
765 return -1;
767 return (st.st_ino == 256) && S_ISDIR(st.st_mode);
772 * Get the default subvolume of a btrfs filesystem
773 * rootdir: btrfs root dir
774 * subvol: this function will save the default subvolume name here
776 static char * get_default_subvol(char * rootdir, char * subvol)
778 struct btrfs_ioctl_search_args args;
779 struct btrfs_ioctl_search_key *sk = &args.key;
780 struct btrfs_ioctl_search_header *sh;
781 int ret, i;
782 int fd;
783 struct btrfs_root_ref *ref;
784 struct btrfs_dir_item *dir_item;
785 unsigned long off = 0;
786 int name_len;
787 char *name;
788 char dirname[4096];
789 u64 defaultsubvolid = 0;
791 ret = test_issubvolume(rootdir);
792 if (ret == 1) {
793 fd = open(rootdir, O_RDONLY);
794 if (fd < 0) {
795 fprintf(stderr, "ERROR: failed to open %s\n", rootdir);
797 ret = fd;
799 if (ret <= 0) {
800 subvol[0] = '\0';
801 return NULL;
804 memset(&args, 0, sizeof(args));
806 /* search in the tree of tree roots */
807 sk->tree_id = 1;
810 * set the min and max to backref keys. The search will
811 * only send back this type of key now.
813 sk->max_type = BTRFS_DIR_ITEM_KEY;
814 sk->min_type = BTRFS_DIR_ITEM_KEY;
817 * set all the other params to the max, we'll take any objectid
818 * and any trans
820 sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
821 sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
823 sk->max_offset = (u64)-1;
824 sk->min_offset = 0;
825 sk->max_transid = (u64)-1;
827 /* just a big number, doesn't matter much */
828 sk->nr_items = 4096;
830 while(1) {
831 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
832 if (ret < 0) {
833 fprintf(stderr, "ERROR: can't perform the search\n");
834 subvol[0] = '\0';
835 return NULL;
837 /* the ioctl returns the number of item it found in nr_items */
838 if (sk->nr_items == 0) {
839 break;
842 off = 0;
845 * for each item, pull the key out of the header and then
846 * read the root_ref item it contains
848 for (i = 0; i < sk->nr_items; i++) {
849 sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
850 off += sizeof(*sh);
851 if (sh->type == BTRFS_DIR_ITEM_KEY) {
852 dir_item = (struct btrfs_dir_item *)(args.buf + off);
853 name_len = dir_item->name_len;
854 name = (char *)(dir_item + 1);
857 /*add_root(&root_lookup, sh->objectid, sh->offset,
858 dir_id, name, name_len);*/
859 strncpy(dirname, name, name_len);
860 dirname[name_len] = '\0';
861 if (strcmp(dirname, "default") == 0) {
862 defaultsubvolid = dir_item->location.objectid;
863 break;
866 off += sh->len;
869 * record the mins in sk so we can make sure the
870 * next search doesn't repeat this root
872 sk->min_objectid = sh->objectid;
873 sk->min_type = sh->type;
874 sk->max_type = sh->type;
875 sk->min_offset = sh->offset;
877 if (defaultsubvolid != 0)
878 break;
879 sk->nr_items = 4096;
880 /* this iteration is done, step forward one root for the next
881 * ioctl
883 if (sk->min_objectid < (u64)-1) {
884 sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
885 sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
886 sk->max_type = BTRFS_ROOT_BACKREF_KEY;
887 sk->min_type = BTRFS_ROOT_BACKREF_KEY;
888 sk->min_offset = 0;
889 } else
890 break;
893 if (defaultsubvolid == 0) {
894 subvol[0] = '\0';
895 return NULL;
898 memset(&args, 0, sizeof(args));
900 /* search in the tree of tree roots */
901 sk->tree_id = 1;
904 * set the min and max to backref keys. The search will
905 * only send back this type of key now.
907 sk->max_type = BTRFS_ROOT_BACKREF_KEY;
908 sk->min_type = BTRFS_ROOT_BACKREF_KEY;
911 * set all the other params to the max, we'll take any objectid
912 * and any trans
914 sk->max_objectid = (u64)-1;
915 sk->max_offset = (u64)-1;
916 sk->max_transid = (u64)-1;
918 /* just a big number, doesn't matter much */
919 sk->nr_items = 4096;
921 while(1) {
922 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
923 if (ret < 0) {
924 fprintf(stderr, "ERROR: can't perform the search\n");
925 subvol[0] = '\0';
926 return NULL;
928 /* the ioctl returns the number of item it found in nr_items */
929 if (sk->nr_items == 0)
930 break;
932 off = 0;
935 * for each item, pull the key out of the header and then
936 * read the root_ref item it contains
938 for (i = 0; i < sk->nr_items; i++) {
939 sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
940 off += sizeof(*sh);
941 if (sh->type == BTRFS_ROOT_BACKREF_KEY) {
942 ref = (struct btrfs_root_ref *)(args.buf + off);
943 name_len = ref->name_len;
944 name = (char *)(ref + 1);
946 if (sh->objectid == defaultsubvolid) {
947 strncpy(subvol, name, name_len);
948 subvol[name_len] = '\0';
949 dprintf("The default subvolume: %s, ID: %llu\n",
950 subvol, sh->objectid);
951 break;
956 off += sh->len;
959 * record the mins in sk so we can make sure the
960 * next search doesn't repeat this root
962 sk->min_objectid = sh->objectid;
963 sk->min_type = sh->type;
964 sk->min_offset = sh->offset;
966 if (subvol[0] != '\0')
967 break;
968 sk->nr_items = 4096;
969 /* this iteration is done, step forward one root for the next
970 * ioctl
972 if (sk->min_objectid < (u64)-1) {
973 sk->min_objectid++;
974 sk->min_type = BTRFS_ROOT_BACKREF_KEY;
975 sk->min_offset = 0;
976 } else
977 break;
979 return subvol;
982 static int install_file(const char *path, int devfd, struct stat *rst)
984 if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS
985 || fs_type == UFS1 || fs_type == UFS2)
986 return ext2_fat_install_file(path, devfd, rst);
987 else if (fs_type == BTRFS)
988 return btrfs_install_file(path, devfd, rst);
989 else if (fs_type == XFS)
990 return xfs_install_file(path, devfd, rst);
992 return 1;
995 #ifdef __KLIBC__
996 static char devname_buf[64];
998 static void device_cleanup(void)
1000 unlink(devname_buf);
1002 #endif
1004 /* Verify that a device fd and a pathname agree.
1005 Return 0 on valid, -1 on error. */
1006 static int validate_device_btrfs(int pathfd, int devfd);
1007 static int validate_device(const char *path, int devfd)
1009 struct stat pst, dst;
1010 struct statfs sfs;
1011 int pfd;
1012 int rv = -1;
1014 pfd = open(path, O_RDONLY|O_DIRECTORY);
1015 if (pfd < 0)
1016 goto err;
1018 if (fstat(pfd, &pst) || fstat(devfd, &dst) || statfs(path, &sfs))
1019 goto err;
1021 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
1022 if (fs_type == BTRFS) {
1023 if (sfs.f_type == BTRFS_SUPER_MAGIC)
1024 rv = validate_device_btrfs(pfd, devfd);
1025 } else {
1026 rv = (pst.st_dev == dst.st_rdev) ? 0 : -1;
1029 err:
1030 if (pfd >= 0)
1031 close(pfd);
1032 return rv;
1035 #ifndef __KLIBC__
1036 static char *find_device(const char *mtab_file, dev_t dev)
1038 struct mntent *mnt;
1039 struct stat dst;
1040 FILE *mtab;
1041 char *devname = NULL;
1042 bool done;
1044 mtab = setmntent(mtab_file, "r");
1045 if (!mtab)
1046 return NULL;
1048 done = false;
1049 while ((mnt = getmntent(mtab))) {
1050 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
1051 switch (fs_type) {
1052 case BTRFS:
1053 if (!strcmp(mnt->mnt_type, "btrfs") &&
1054 !stat(mnt->mnt_dir, &dst) &&
1055 dst.st_dev == dev) {
1056 if (!subvol[0])
1057 get_default_subvol(mnt->mnt_dir, subvol);
1058 done = true;
1060 break;
1061 case EXT2:
1062 if ((!strcmp(mnt->mnt_type, "ext2") ||
1063 !strcmp(mnt->mnt_type, "ext3") ||
1064 !strcmp(mnt->mnt_type, "ext4")) &&
1065 !stat(mnt->mnt_fsname, &dst) &&
1066 dst.st_rdev == dev) {
1067 done = true;
1068 break;
1070 case VFAT:
1071 if ((!strcmp(mnt->mnt_type, "vfat")) &&
1072 !stat(mnt->mnt_fsname, &dst) &&
1073 dst.st_rdev == dev) {
1074 done = true;
1075 break;
1077 case NTFS:
1078 if ((!strcmp(mnt->mnt_type, "fuseblk") /* ntfs-3g */ ||
1079 !strcmp(mnt->mnt_type, "ntfs")) &&
1080 !stat(mnt->mnt_fsname, &dst) &&
1081 dst.st_rdev == dev) {
1082 done = true;
1083 break;
1086 break;
1087 case XFS:
1088 if (!strcmp(mnt->mnt_type, "xfs") && !stat(mnt->mnt_fsname, &dst) &&
1089 dst.st_rdev == dev) {
1090 done = true;
1091 break;
1094 break;
1095 case UFS1:
1096 case UFS2:
1097 if (!strcmp(mnt->mnt_type, "ufs") && !stat(mnt->mnt_fsname, &dst) &&
1098 dst.st_rdev == dev) {
1099 done = true;
1102 break;
1103 case NONE:
1104 break;
1107 if (done) {
1108 devname = strdup(mnt->mnt_fsname);
1109 break;
1113 endmntent(mtab);
1115 return devname;
1117 #endif
1120 * On newer Linux kernels we can use sysfs to get a backwards mapping
1121 * from device names to standard filenames
1123 static char *find_device_sysfs(dev_t dev)
1125 char sysname[64];
1126 char linkname[PATH_MAX];
1127 ssize_t llen;
1128 char *p, *q;
1129 char *buf = NULL;
1130 struct stat st;
1132 snprintf(sysname, sizeof sysname, "/sys/dev/block/%u:%u",
1133 major(dev), minor(dev));
1135 llen = readlink(sysname, linkname, sizeof linkname);
1136 if (llen < 0 || llen >= sizeof linkname)
1137 goto err;
1139 linkname[llen] = '\0';
1141 p = strrchr(linkname, '/');
1142 p = p ? p+1 : linkname; /* Leave basename */
1144 buf = q = malloc(strlen(p) + 6);
1145 if (!buf)
1146 goto err;
1148 memcpy(q, "/dev/", 5);
1149 q += 5;
1151 while (*p) {
1152 *q++ = (*p == '!') ? '/' : *p;
1153 p++;
1156 *q = '\0';
1158 if (!stat(buf, &st) && st.st_dev == dev)
1159 return buf; /* Found it! */
1161 err:
1162 if (buf)
1163 free(buf);
1164 return NULL;
1167 static const char *find_device_mountinfo(const char *path, dev_t dev)
1169 const struct mountinfo *m;
1170 struct stat st;
1172 m = find_mount(path, NULL);
1173 if (!m)
1174 return NULL;
1176 if (m->devpath[0] == '/' && m->dev == dev &&
1177 !stat(m->devpath, &st) && S_ISBLK(st.st_mode) && st.st_rdev == dev)
1178 return m->devpath;
1179 else
1180 return NULL;
1183 static int validate_device_btrfs(int pfd, int dfd)
1185 struct btrfs_ioctl_fs_info_args fsinfo;
1186 static struct btrfs_ioctl_dev_info_args devinfo;
1187 struct btrfs_super_block sb2;
1189 if (ioctl(pfd, BTRFS_IOC_FS_INFO, &fsinfo))
1190 return -1;
1192 /* We do not support multi-device btrfs yet */
1193 if (fsinfo.num_devices != 1)
1194 return -1;
1196 /* The one device will have the max devid */
1197 memset(&devinfo, 0, sizeof devinfo);
1198 devinfo.devid = fsinfo.max_id;
1199 if (ioctl(pfd, BTRFS_IOC_DEV_INFO, &devinfo))
1200 return -1;
1202 if (devinfo.path[0] != '/')
1203 return -1;
1205 if (xpread(dfd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET) != sizeof sb2)
1206 return -1;
1208 if (memcmp(sb2.magic, BTRFS_MAGIC, BTRFS_MAGIC_L))
1209 return -1;
1211 if (memcmp(sb2.fsid, fsinfo.fsid, sizeof fsinfo.fsid))
1212 return -1;
1214 if (sb2.num_devices != 1)
1215 return -1;
1217 if (sb2.dev_item.devid != devinfo.devid)
1218 return -1;
1220 if (memcmp(sb2.dev_item.uuid, devinfo.uuid, sizeof devinfo.uuid))
1221 return -1;
1223 if (memcmp(sb2.dev_item.fsid, fsinfo.fsid, sizeof fsinfo.fsid))
1224 return -1;
1226 return 0; /* It's good! */
1229 static const char *find_device_btrfs(const char *path)
1231 int pfd, dfd;
1232 struct btrfs_ioctl_fs_info_args fsinfo;
1233 static struct btrfs_ioctl_dev_info_args devinfo;
1234 const char *rv = NULL;
1236 pfd = dfd = -1;
1238 pfd = open(path, O_RDONLY);
1239 if (pfd < 0)
1240 goto err;
1242 if (ioctl(pfd, BTRFS_IOC_FS_INFO, &fsinfo))
1243 goto err;
1245 /* We do not support multi-device btrfs yet */
1246 if (fsinfo.num_devices != 1)
1247 goto err;
1249 /* The one device will have the max devid */
1250 memset(&devinfo, 0, sizeof devinfo);
1251 devinfo.devid = fsinfo.max_id;
1252 if (ioctl(pfd, BTRFS_IOC_DEV_INFO, &devinfo))
1253 goto err;
1255 if (devinfo.path[0] != '/')
1256 goto err;
1258 dfd = open((const char *)devinfo.path, O_RDONLY);
1259 if (dfd < 0)
1260 goto err;
1262 if (!validate_device_btrfs(pfd, dfd))
1263 rv = (const char *)devinfo.path; /* It's good! */
1265 err:
1266 if (pfd >= 0)
1267 close(pfd);
1268 if (dfd >= 0)
1269 close(dfd);
1270 return rv;
1273 static char *dupname(const char *name)
1275 char *out = NULL;
1276 int len = 0;
1277 if (name)
1278 len = strlen(name);
1279 if (len > 0)
1280 out = strndup(name, len);
1281 return out;
1284 static char *get_devname(const char *path)
1286 char *devname = NULL;
1287 struct stat st;
1288 struct statfs sfs;
1290 if (stat(path, &st) || !S_ISDIR(st.st_mode)) {
1291 fprintf(stderr, "%s: Not a directory: %s\n", program, path);
1292 return devname;
1294 if (statfs(path, &sfs)) {
1295 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
1296 return devname;
1299 if (opt.device)
1300 devname = strdup(opt.device);
1302 if (!devname){
1303 if (fs_type == BTRFS) {
1304 /* For btrfs try to get the device name from btrfs itself */
1305 devname = dupname(find_device_btrfs(path));
1309 if (!devname) {
1310 devname = dupname(find_device_mountinfo(path, st.st_dev));
1313 #ifdef __KLIBC__
1314 if (!devname) {
1315 devname = find_device_sysfs(st.st_dev);
1317 if (!devname) {
1318 /* klibc doesn't have getmntent and friends; instead, just create
1319 a new device with the appropriate device type */
1320 snprintf(devname_buf, sizeof devname_buf, "/tmp/dev-%u:%u",
1321 major(st.st_dev), minor(st.st_dev));
1323 if (mknod(devname_buf, S_IFBLK | 0600, st.st_dev)) {
1324 fprintf(stderr, "%s: cannot create device %s\n", program, devname);
1325 return devname;
1328 atexit(device_cleanup); /* unlink the device node on exit */
1329 devname = dupname(devname_buf);
1332 #else
1333 if (!devname) {
1334 devname = find_device("/proc/mounts", st.st_dev);
1336 if (!devname) {
1337 /* Didn't find it in /proc/mounts, try /etc/mtab */
1338 devname = find_device("/etc/mtab", st.st_dev);
1340 if (!devname) {
1341 devname = find_device_sysfs(st.st_dev);
1343 fprintf(stderr, "%s: cannot find device for path %s\n", program, path);
1344 return devname;
1347 fprintf(stderr, "%s is device %s\n", path, devname);
1349 #endif
1350 return devname;
1353 static int open_device(const char *path, struct stat *st, char **_devname)
1355 int devfd;
1356 char *devname = NULL;
1357 struct statfs sfs;
1359 if (st)
1360 if (stat(path, st) || !S_ISDIR(st->st_mode)) {
1361 fprintf(stderr, "%s: Not a directory: %s\n", program, path);
1362 return -1;
1365 if (statfs(path, &sfs)) {
1366 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
1367 return -1;
1370 if (sfs.f_type == EXT2_SUPER_MAGIC)
1371 fs_type = EXT2;
1372 else if (sfs.f_type == BTRFS_SUPER_MAGIC)
1373 fs_type = BTRFS;
1374 else if (sfs.f_type == MSDOS_SUPER_MAGIC)
1375 fs_type = VFAT;
1376 else if (sfs.f_type == NTFS_SB_MAGIC ||
1377 sfs.f_type == FUSE_SUPER_MAGIC /* ntfs-3g */)
1378 fs_type = NTFS;
1379 else if (sfs.f_type == XFS_SUPER_MAGIC)
1380 fs_type = XFS;
1381 else if (sfs.f_type == UFS1_SUPER_MAGIC)
1382 fs_type = UFS1;
1383 else if (sfs.f_type == UFS2_SUPER_MAGIC)
1384 fs_type = UFS2;
1386 if (!fs_type) {
1387 fprintf(stderr,
1388 "%s: not a fat, ntfs, ext2/3/4, btrfs, xfs or"
1389 "ufs1/2 filesystem: %s\n",
1390 program, path);
1391 return -1;
1394 devfd = -1;
1395 devname = get_devname(path);
1397 if ((devfd = open(devname, O_RDWR | O_SYNC)) < 0) {
1398 fprintf(stderr, "%s: cannot open device %s\n", program, devname);
1399 free(devname);
1400 return -1;
1403 /* Verify that the device we opened is the device intended */
1404 if (validate_device(path, devfd)) {
1405 fprintf(stderr, "%s: path %s doesn't match device %s\n",
1406 program, path, devname);
1407 free(devname);
1408 close(devfd);
1409 return -1;
1411 if (_devname)
1412 *_devname = devname;
1413 else
1414 free(devname);
1415 return devfd;
1418 static int btrfs_read_adv(int devfd)
1420 if (xpread(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET)
1421 != 2 * ADV_SIZE)
1422 return -1;
1424 return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
1427 static inline int xfs_read_adv(int devfd)
1429 const size_t adv_size = 2 * ADV_SIZE;
1431 if (xpread(devfd, syslinux_adv, adv_size, boot_image_len) != adv_size)
1432 return -1;
1434 return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
1437 static int ext_read_adv(const char *path, int devfd, const char **namep)
1439 int err;
1440 const char *name;
1442 if (fs_type == BTRFS) {
1443 /* btrfs "ldlinux.sys" is in 64k blank area */
1444 return btrfs_read_adv(devfd);
1445 } else if (fs_type == XFS) {
1446 /* XFS "ldlinux.sys" is in the first 2048 bytes of the primary AG */
1447 return xfs_read_adv(devfd);
1448 } else {
1449 err = read_adv(path, name = "ldlinux.sys");
1450 if (err == 2) /* ldlinux.sys does not exist */
1451 err = read_adv(path, name = "extlinux.sys");
1452 if (namep)
1453 *namep = name;
1454 return err;
1458 static int ext_write_adv(const char *path, const char *cfg, int devfd)
1460 if (fs_type == BTRFS) { /* btrfs "ldlinux.sys" is in 64k blank area */
1461 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE,
1462 BTRFS_ADV_OFFSET) != 2 * ADV_SIZE) {
1463 perror("writing adv");
1464 return 1;
1466 return 0;
1468 return write_adv(path, cfg);
1471 static int install_loader(const char *path, int update_only)
1473 struct stat st, fst;
1474 int devfd, rv;
1475 char *devname = NULL;
1477 devfd = open_device(path, &st, &devname);
1478 if (devfd < 0)
1479 return 1;
1481 if (update_only && !syslinux_already_installed(devfd)) {
1482 fprintf(stderr, "%s: no previous syslinux boot sector found\n",
1483 program);
1484 close(devfd);
1485 return 1;
1488 /* Read a pre-existing ADV, if already installed */
1489 if (opt.reset_adv) {
1490 syslinux_reset_adv(syslinux_adv);
1491 } else if (ext_read_adv(path, devfd, NULL) < 0) {
1492 close(devfd);
1493 return 1;
1496 if (modify_adv() < 0) {
1497 close(devfd);
1498 return 1;
1501 /* Install ldlinux.sys */
1502 if (install_file(path, devfd, &fst)) {
1503 close(devfd);
1504 return 1;
1506 if (fst.st_dev != st.st_dev) {
1507 fprintf(stderr, "%s: file system changed under us - aborting!\n",
1508 program);
1509 close(devfd);
1510 return 1;
1513 sync();
1514 rv = install_bootblock(devfd, devname);
1515 free(devname);
1516 close(devfd);
1517 sync();
1519 return rv;
1523 * Modify the ADV of an existing installation
1525 int modify_existing_adv(const char *path)
1527 const char *filename;
1528 int devfd;
1530 devfd = open_device(path, NULL, NULL);
1531 if (devfd < 0)
1532 return 1;
1534 if (ext_read_adv(path, devfd, &filename) < 0) {
1535 close(devfd);
1536 return 1;
1538 if (modify_adv() < 0) {
1539 close(devfd);
1540 return 1;
1542 if (ext_write_adv(path, filename, devfd) < 0) {
1543 close(devfd);
1544 return 1;
1546 close(devfd);
1547 return 0;
1550 int main(int argc, char *argv[])
1552 parse_options(argc, argv, MODE_EXTLINUX);
1554 if (!opt.directory || opt.install_mbr || opt.activate_partition)
1555 usage(EX_USAGE, 0);
1557 if (opt.update_only == -1) {
1558 if (opt.reset_adv || opt.set_once || opt.menu_save)
1559 return modify_existing_adv(opt.directory);
1560 else
1561 usage(EX_USAGE, MODE_EXTLINUX);
1564 return install_loader(opt.directory, opt.update_only);