Releasing debian version 3:6.03+dfsg-10.
[syslinux-debian.git] / extlinux / main.c
blob09740bd75a1a8587c80d3b8cd2f1ddd03324d148
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 an 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 "syslxfs.h"
60 #include "setadv.h"
61 #include "syslxopt.h" /* unified options */
62 #include "mountinfo.h"
64 #ifdef DEBUG
65 # define dprintf printf
66 #else
67 # define dprintf(...) ((void)0)
68 #endif
70 #ifndef EXT2_SUPER_OFFSET
71 #define EXT2_SUPER_OFFSET 1024
72 #endif
74 /* Since we have unused 2048 bytes in the primary AG of an XFS partition,
75 * we will use the first 0~512 bytes starting from 2048 for the Syslinux
76 * boot sector.
78 #define XFS_BOOTSECT_OFFSET (4 << SECTOR_SHIFT)
79 #define XFS_SUPPORTED_BLOCKSIZE 4096 /* 4 KiB filesystem block size */
82 * btrfs has two discontiguous areas reserved for the boot loader.
83 * Use the first one (Boot Area A) for the boot sector and the ADV,
84 * and the second one for "ldlinux.sys".
86 #define BTRFS_EXTLINUX_OFFSET BTRFS_BOOT_AREA_B_OFFSET
87 #define BTRFS_EXTLINUX_SIZE BTRFS_BOOT_AREA_B_SIZE
88 #define BTRFS_SUBVOL_MAX 256 /* By btrfs specification */
89 static char subvol[BTRFS_SUBVOL_MAX];
91 #define BTRFS_ADV_OFFSET (BTRFS_BOOT_AREA_A_OFFSET + BTRFS_BOOT_AREA_A_SIZE \
92 - 2*ADV_SIZE)
95 * Get the size of a block device
97 static uint64_t get_size(int devfd)
99 uint64_t bytes;
100 uint32_t sects;
101 struct stat st;
103 #ifdef BLKGETSIZE64
104 if (!ioctl(devfd, BLKGETSIZE64, &bytes))
105 return bytes;
106 #endif
107 if (!ioctl(devfd, BLKGETSIZE, &sects))
108 return (uint64_t) sects << 9;
109 else if (!fstat(devfd, &st) && st.st_size)
110 return st.st_size;
111 else
112 return 0;
116 * Get device geometry and partition offset
118 struct geometry_table {
119 uint64_t bytes;
120 struct hd_geometry g;
123 static int sysfs_get_offset(int devfd, unsigned long *start)
125 struct stat st;
126 char sysfs_name[128];
127 FILE *f;
128 int rv;
130 if (fstat(devfd, &st))
131 return -1;
133 if ((size_t)snprintf(sysfs_name, sizeof sysfs_name,
134 "/sys/dev/block/%u:%u/start",
135 major(st.st_rdev), minor(st.st_rdev))
136 >= sizeof sysfs_name)
137 return -1;
139 f = fopen(sysfs_name, "r");
140 if (!f)
141 return -1;
143 rv = fscanf(f, "%lu", start);
144 fclose(f);
146 return (rv == 1) ? 0 : -1;
149 /* Standard floppy disk geometries, plus LS-120. Zipdisk geometry
150 (x/64/32) is the final fallback. I don't know what LS-240 has
151 as its geometry, since I don't have one and don't know anyone that does,
152 and Google wasn't helpful... */
153 static const struct geometry_table standard_geometries[] = {
154 {360 * 1024, {2, 9, 40, 0}},
155 {720 * 1024, {2, 9, 80, 0}},
156 {1200 * 1024, {2, 15, 80, 0}},
157 {1440 * 1024, {2, 18, 80, 0}},
158 {1680 * 1024, {2, 21, 80, 0}},
159 {1722 * 1024, {2, 21, 80, 0}},
160 {2880 * 1024, {2, 36, 80, 0}},
161 {3840 * 1024, {2, 48, 80, 0}},
162 {123264 * 1024, {8, 32, 963, 0}}, /* LS120 */
163 {0, {0, 0, 0, 0}}
166 int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo)
168 struct floppy_struct fd_str;
169 struct loop_info li;
170 struct loop_info64 li64;
171 const struct geometry_table *gp;
172 int rv = 0;
174 memset(geo, 0, sizeof *geo);
176 if (!ioctl(devfd, HDIO_GETGEO, geo)) {
177 goto ok;
178 } else if (!ioctl(devfd, FDGETPRM, &fd_str)) {
179 geo->heads = fd_str.head;
180 geo->sectors = fd_str.sect;
181 geo->cylinders = fd_str.track;
182 geo->start = 0;
183 goto ok;
186 /* Didn't work. Let's see if this is one of the standard geometries */
187 for (gp = standard_geometries; gp->bytes; gp++) {
188 if (gp->bytes == totalbytes) {
189 memcpy(geo, &gp->g, sizeof *geo);
190 goto ok;
194 /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is
195 what zipdisks use, so this would help if someone has a USB key that
196 they're booting in USB-ZIP mode. */
198 geo->heads = opt.heads ? : 64;
199 geo->sectors = opt.sectors ? : 32;
200 geo->cylinders = totalbytes / (geo->heads * geo->sectors << SECTOR_SHIFT);
201 geo->start = 0;
203 if (!opt.sectors && !opt.heads) {
204 fprintf(stderr,
205 "Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n"
206 " (on hard disks, this is usually harmless.)\n",
207 geo->heads, geo->sectors);
208 rv = 1; /* Suboptimal result */
212 /* If this is a loopback device, try to set the start */
213 if (!ioctl(devfd, LOOP_GET_STATUS64, &li64))
214 geo->start = li64.lo_offset >> SECTOR_SHIFT;
215 else if (!ioctl(devfd, LOOP_GET_STATUS, &li))
216 geo->start = (unsigned int)li.lo_offset >> SECTOR_SHIFT;
217 else if (!sysfs_get_offset(devfd, &geo->start)) {
218 /* OK */
221 return rv;
225 * Query the device geometry and put it into the boot sector.
226 * Map the file and put the map in the boot sector and file.
227 * Stick the "current directory" inode number into the file.
229 * Returns the number of modified bytes in the boot file.
231 static int patch_file_and_bootblock(int fd, const char *dir, int devfd)
233 struct stat dirst, xdst;
234 struct hd_geometry geo;
235 sector_t *sectp;
236 uint64_t totalbytes, totalsectors;
237 int nsect;
238 struct fat_boot_sector *sbs;
239 char *dirpath, *subpath, *xdirpath;
240 int rv;
242 dirpath = realpath(dir, NULL);
243 if (!dirpath || stat(dir, &dirst)) {
244 perror("accessing install directory");
245 exit(255); /* This should never happen */
248 if (lstat(dirpath, &xdst) ||
249 dirst.st_ino != xdst.st_ino ||
250 dirst.st_dev != xdst.st_dev) {
251 perror("realpath returned nonsense");
252 exit(255);
255 subpath = strchr(dirpath, '\0');
256 for (;;) {
257 if (*subpath == '/') {
258 if (subpath > dirpath) {
259 *subpath = '\0';
260 xdirpath = dirpath;
261 } else {
262 xdirpath = "/";
264 if (lstat(xdirpath, &xdst) || dirst.st_dev != xdst.st_dev) {
265 subpath = strchr(subpath+1, '/');
266 if (!subpath)
267 subpath = "/"; /* It's the root of the filesystem */
268 break;
270 *subpath = '/';
273 if (subpath == dirpath)
274 break;
276 subpath--;
279 /* Now subpath should contain the path relative to the fs base */
280 dprintf("subpath = %s\n", subpath);
282 totalbytes = get_size(devfd);
283 get_geometry(devfd, totalbytes, &geo);
285 if (opt.heads)
286 geo.heads = opt.heads;
287 if (opt.sectors)
288 geo.sectors = opt.sectors;
290 /* Patch this into a fake FAT superblock. This isn't because
291 FAT is a good format in any way, it's because it lets the
292 early bootstrap share code with the FAT version. */
293 dprintf("heads = %u, sect = %u\n", geo.heads, geo.sectors);
295 sbs = (struct fat_boot_sector *)syslinux_bootsect;
297 totalsectors = totalbytes >> SECTOR_SHIFT;
298 if (totalsectors >= 65536) {
299 set_16(&sbs->bsSectors, 0);
300 } else {
301 set_16(&sbs->bsSectors, totalsectors);
303 set_32(&sbs->bsHugeSectors, totalsectors);
305 set_16(&sbs->bsBytesPerSec, SECTOR_SIZE);
306 set_16(&sbs->bsSecPerTrack, geo.sectors);
307 set_16(&sbs->bsHeads, geo.heads);
308 set_32(&sbs->bsHiddenSecs, geo.start);
310 /* Construct the boot file map */
312 dprintf("directory inode = %lu\n", (unsigned long)dirst.st_ino);
313 nsect = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
314 nsect += 2; /* Two sectors for the ADV */
315 sectp = alloca(sizeof(sector_t) * nsect);
316 if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS ||
317 fs_type == XFS || fs_type == UFS1 || fs_type == UFS2) {
318 if (sectmap(fd, sectp, nsect)) {
319 perror("bmap");
320 exit(1);
322 } else if (fs_type == BTRFS) {
323 int i;
324 sector_t *sp = sectp;
326 for (i = 0; i < nsect - 2; i++)
327 *sp++ = BTRFS_EXTLINUX_OFFSET/SECTOR_SIZE + i;
328 for (i = 0; i < 2; i++)
329 *sp++ = BTRFS_ADV_OFFSET/SECTOR_SIZE + i;
332 /* Create the modified image in memory */
333 rv = syslinux_patch(sectp, nsect, opt.stupid_mode,
334 opt.raid_mode, subpath, subvol);
336 free(dirpath);
337 return rv;
341 * Install the boot block on the specified device.
342 * Must be run AFTER install_file()!
344 int install_bootblock(int fd, const char *device)
346 struct ext2_super_block sb;
347 struct btrfs_super_block sb2;
348 struct fat_boot_sector sb3;
349 struct ntfs_boot_sector sb4;
350 xfs_sb_t sb5;
351 struct ufs_super_block sb6;
352 bool ok = false;
354 if (fs_type == EXT2) {
355 if (xpread(fd, &sb, sizeof sb, EXT2_SUPER_OFFSET) != sizeof sb) {
356 perror("reading superblock");
357 return 1;
360 if (sb.s_magic == EXT2_SUPER_MAGIC)
361 ok = true;
362 } else if (fs_type == BTRFS) {
363 if (xpread(fd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET)
364 != sizeof sb2) {
365 perror("reading superblock");
366 return 1;
368 if (!memcmp(sb2.magic, BTRFS_MAGIC, BTRFS_MAGIC_L))
369 ok = true;
370 } else if (fs_type == VFAT) {
371 if (xpread(fd, &sb3, sizeof sb3, 0) != sizeof sb3) {
372 perror("reading fat superblock");
373 return 1;
376 if (fat_check_sb_fields(&sb3))
377 ok = true;
378 } else if (fs_type == NTFS) {
379 if (xpread(fd, &sb4, sizeof(sb4), 0) != sizeof(sb4)) {
380 perror("reading ntfs superblock");
381 return 1;
384 if (ntfs_check_sb_fields(&sb4))
385 ok = true;
386 } else if (fs_type == XFS) {
387 if (xpread(fd, &sb5, sizeof sb5, 0) != sizeof sb5) {
388 perror("reading xfs superblock");
389 return 1;
392 if (sb5.sb_magicnum == *(u32 *)XFS_SB_MAGIC) {
393 if (be32_to_cpu(sb5.sb_blocksize) != XFS_SUPPORTED_BLOCKSIZE) {
394 fprintf(stderr,
395 "You need to have 4 KiB filesystem block size for "
396 " being able to install Syslinux in your XFS "
397 "partition (because there is no enough space in MBR to "
398 "determine where Syslinux bootsector can be installed "
399 "regardless the filesystem block size)\n");
400 return 1;
403 ok = true;
405 } else if (fs_type == UFS1 || fs_type == UFS2) {
406 uint32_t sblock_off = (fs_type == UFS1) ?
407 SBLOCK_UFS1 : SBLOCK_UFS2;
408 uint32_t ufs_smagic = (fs_type == UFS1) ?
409 UFS1_SUPER_MAGIC : UFS2_SUPER_MAGIC;
411 if (xpread(fd, &sb6, sizeof sb6, sblock_off) != sizeof sb6) {
412 perror("reading superblock");
413 return 1;
416 if (sb6.fs_magic == ufs_smagic)
417 ok = true;
420 if (!ok) {
421 fprintf(stderr,
422 "no fat, ntfs, ext2/3/4, btrfs, xfs "
423 "or ufs1/2 superblock found on %s\n",
424 device);
425 return 1;
428 if (fs_type == VFAT) {
429 struct fat_boot_sector *sbs = (struct fat_boot_sector *)syslinux_bootsect;
430 if (xpwrite(fd, &sbs->FAT_bsHead, FAT_bsHeadLen, 0) != FAT_bsHeadLen ||
431 xpwrite(fd, &sbs->FAT_bsCode, FAT_bsCodeLen,
432 offsetof(struct fat_boot_sector, FAT_bsCode)) != FAT_bsCodeLen) {
433 perror("writing fat bootblock");
434 return 1;
436 } else if (fs_type == NTFS) {
437 struct ntfs_boot_sector *sbs =
438 (struct ntfs_boot_sector *)syslinux_bootsect;
439 if (xpwrite(fd, &sbs->NTFS_bsHead,
440 NTFS_bsHeadLen, 0) != NTFS_bsHeadLen ||
441 xpwrite(fd, &sbs->NTFS_bsCode, NTFS_bsCodeLen,
442 offsetof(struct ntfs_boot_sector,
443 NTFS_bsCode)) != NTFS_bsCodeLen) {
444 perror("writing ntfs bootblock");
445 return 1;
447 } else if (fs_type == XFS) {
448 if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len,
449 XFS_BOOTSECT_OFFSET) != syslinux_bootsect_len) {
450 perror("writing xfs bootblock");
451 return 1;
453 } else {
454 if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len, 0)
455 != syslinux_bootsect_len) {
456 perror("writing bootblock");
457 return 1;
461 return 0;
464 static int rewrite_boot_image(int devfd, const char *path, const char *filename)
466 int fd;
467 int ret;
468 int modbytes;
470 /* Let's create LDLINUX.SYS file again (if it already exists, of course) */
471 fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
472 S_IRUSR | S_IRGRP | S_IROTH);
473 if (fd < 0) {
474 perror(filename);
475 return -1;
478 /* Write boot image data into LDLINUX.SYS file */
479 ret = xpwrite(fd, (const char _force *)boot_image, boot_image_len, 0);
480 if (ret != boot_image_len) {
481 perror("writing bootblock");
482 goto error;
485 /* Write ADV */
486 ret = xpwrite(fd, syslinux_adv, 2 * ADV_SIZE, boot_image_len);
487 if (ret != 2 * ADV_SIZE) {
488 fprintf(stderr, "%s: write failure on %s\n", program, filename);
489 goto error;
492 /* Map the file, and patch the initial sector accordingly */
493 modbytes = patch_file_and_bootblock(fd, path, devfd);
495 /* Write the patch area again - this relies on the file being overwritten
496 * in place! */
497 ret = xpwrite(fd, (const char _force *)boot_image, modbytes, 0);
498 if (ret != modbytes) {
499 fprintf(stderr, "%s: write failure on %s\n", program, filename);
500 goto error;
503 return fd;
505 error:
506 close(fd);
508 return -1;
511 int ext2_fat_install_file(const char *path, int devfd, struct stat *rst)
513 char *file, *oldfile, *c32file;
514 int fd = -1, dirfd = -1;
515 int r1, r2, r3;
517 r1 = asprintf(&file, "%s%sldlinux.sys",
518 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
519 r2 = asprintf(&oldfile, "%s%sextlinux.sys",
520 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
521 r3 = asprintf(&c32file, "%s%sldlinux.c32",
522 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
523 if (r1 < 0 || !file || r2 < 0 || !oldfile || r3 < 0 || !c32file) {
524 perror(program);
525 return 1;
528 dirfd = open(path, O_RDONLY | O_DIRECTORY);
529 if (dirfd < 0) {
530 perror(path);
531 goto bail;
534 fd = open(file, O_RDONLY);
535 if (fd < 0) {
536 if (errno != ENOENT) {
537 perror(file);
538 goto bail;
540 } else {
541 clear_attributes(fd);
543 close(fd);
545 fd = rewrite_boot_image(devfd, path, file);
546 if (fd < 0)
547 goto bail;
549 /* Attempt to set immutable flag and remove all write access */
550 /* Only set immutable flag if file is owned by root */
551 set_attributes(fd);
553 if (fstat(fd, rst)) {
554 perror(file);
555 goto bail;
558 close(dirfd);
559 close(fd);
561 /* Look if we have the old filename */
562 fd = open(oldfile, O_RDONLY);
563 if (fd >= 0) {
564 clear_attributes(fd);
565 close(fd);
566 unlink(oldfile);
569 fd = open(c32file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
570 S_IRUSR | S_IRGRP | S_IROTH);
571 if (fd < 0) {
572 perror(c32file);
573 goto bail;
576 r3 = xpwrite(fd, (const char _force *)syslinux_ldlinuxc32,
577 syslinux_ldlinuxc32_len, 0);
578 if (r3 != syslinux_ldlinuxc32_len) {
579 fprintf(stderr, "%s: write failure on %s\n", program, c32file);
580 goto bail;
583 free(file);
584 free(oldfile);
585 free(c32file);
586 return 0;
588 bail:
589 if (dirfd >= 0)
590 close(dirfd);
591 if (fd >= 0)
592 close(fd);
594 free(file);
595 free(oldfile);
596 free(c32file);
597 return 1;
600 /* btrfs has to install the ldlinux.sys in the first 64K blank area, which
601 is not managered by btrfs tree, so actually this is not installed as files.
602 since the cow feature of btrfs will move the ldlinux.sys every where */
603 int btrfs_install_file(const char *path, int devfd, struct stat *rst)
605 char *file;
606 int fd, rv;
608 patch_file_and_bootblock(-1, path, devfd);
609 if (xpwrite(devfd, (const char _force *)boot_image,
610 boot_image_len, BTRFS_EXTLINUX_OFFSET)
611 != boot_image_len) {
612 perror("writing bootblock");
613 return 1;
615 dprintf("write boot_image to 0x%x\n", BTRFS_EXTLINUX_OFFSET);
616 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET)
617 != 2 * ADV_SIZE) {
618 perror("writing adv");
619 return 1;
621 dprintf("write adv to 0x%x\n", BTRFS_ADV_OFFSET);
622 if (stat(path, rst)) {
623 perror(path);
624 return 1;
628 * Note that we *can* install ldinux.c32 as a regular file because
629 * it doesn't need to be within the first 64K. The Syslinux core
630 * has enough smarts to search the btrfs dirs and find this file.
632 rv = asprintf(&file, "%s%sldlinux.c32",
633 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
634 if (rv < 0 || !file) {
635 perror(program);
636 return 1;
639 fd = open(file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
640 S_IRUSR | S_IRGRP | S_IROTH);
641 if (fd < 0) {
642 perror(file);
643 free(file);
644 return 1;
647 rv = xpwrite(fd, (const char _force *)syslinux_ldlinuxc32,
648 syslinux_ldlinuxc32_len, 0);
649 if (rv != (int)syslinux_ldlinuxc32_len) {
650 fprintf(stderr, "%s: write failure on %s\n", program, file);
651 rv = 1;
652 } else
653 rv = 0;
655 close(fd);
656 free(file);
657 return rv;
661 * Due to historical reasons (SGI IRIX's design of disk layouts), the first
662 * sector in the primary AG on XFS filesystems contains the superblock, which is
663 * a problem with bootloaders that rely on BIOSes (that load VBRs which are
664 * (located in the first sector of the partition).
666 * Thus, we need to handle this issue, otherwise Syslinux will damage the XFS's
667 * superblock.
669 static int xfs_install_file(const char *path, int devfd, struct stat *rst)
671 static char file[PATH_MAX + 1];
672 static char c32file[PATH_MAX + 1];
673 int dirfd = -1;
674 int fd = -1;
675 int retval;
677 snprintf(file, PATH_MAX + 1, "%s%sldlinux.sys", path,
678 path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
679 snprintf(c32file, PATH_MAX + 1, "%s%sldlinux.c32", path,
680 path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
682 dirfd = open(path, O_RDONLY | O_DIRECTORY);
683 if (dirfd < 0) {
684 perror(path);
685 goto bail;
688 fd = open(file, O_RDONLY);
689 if (fd < 0) {
690 if (errno != ENOENT) {
691 perror(file);
692 goto bail;
694 } else {
695 clear_attributes(fd);
698 close(fd);
700 fd = rewrite_boot_image(devfd, path, file);
701 if (fd < 0)
702 goto bail;
704 /* Attempt to set immutable flag and remove all write access */
705 /* Only set immutable flag if file is owned by root */
706 set_attributes(fd);
708 if (fstat(fd, rst)) {
709 perror(file);
710 goto bail;
713 close(dirfd);
714 close(fd);
716 dirfd = -1;
717 fd = -1;
719 fd = open(c32file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
720 S_IRUSR | S_IRGRP | S_IROTH);
721 if (fd < 0) {
722 perror(c32file);
723 goto bail;
726 retval = xpwrite(fd, (const char _force *)syslinux_ldlinuxc32,
727 syslinux_ldlinuxc32_len, 0);
728 if (retval != (int)syslinux_ldlinuxc32_len) {
729 fprintf(stderr, "%s: write failure on %s\n", program, file);
730 goto bail;
733 close(fd);
735 sync();
737 return 0;
739 bail:
740 if (dirfd >= 0)
741 close(dirfd);
743 if (fd >= 0)
744 close(fd);
746 return 1;
750 * * test if path is a subvolume:
751 * * this function return
752 * * 0-> path exists but it is not a subvolume
753 * * 1-> path exists and it is a subvolume
754 * * -1 -> path is unaccessible
755 * */
756 static int test_issubvolume(char *path)
759 struct stat st;
760 int res;
762 res = stat(path, &st);
763 if(res < 0 )
764 return -1;
766 return (st.st_ino == 256) && S_ISDIR(st.st_mode);
771 * Get the default subvolume of a btrfs filesystem
772 * rootdir: btrfs root dir
773 * subvol: this function will save the default subvolume name here
775 static char * get_default_subvol(char * rootdir, char * subvol)
777 struct btrfs_ioctl_search_args args;
778 struct btrfs_ioctl_search_key *sk = &args.key;
779 struct btrfs_ioctl_search_header *sh;
780 int ret, i;
781 int fd;
782 struct btrfs_root_ref *ref;
783 struct btrfs_dir_item *dir_item;
784 unsigned long off = 0;
785 int name_len;
786 char *name;
787 char dirname[4096];
788 u64 defaultsubvolid = 0;
790 ret = test_issubvolume(rootdir);
791 if (ret == 1) {
792 fd = open(rootdir, O_RDONLY);
793 if (fd < 0) {
794 fprintf(stderr, "ERROR: failed to open %s\n", rootdir);
796 ret = fd;
798 if (ret <= 0) {
799 subvol[0] = '\0';
800 return NULL;
803 memset(&args, 0, sizeof(args));
805 /* search in the tree of tree roots */
806 sk->tree_id = 1;
809 * set the min and max to backref keys. The search will
810 * only send back this type of key now.
812 sk->max_type = BTRFS_DIR_ITEM_KEY;
813 sk->min_type = BTRFS_DIR_ITEM_KEY;
816 * set all the other params to the max, we'll take any objectid
817 * and any trans
819 sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
820 sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
822 sk->max_offset = (u64)-1;
823 sk->min_offset = 0;
824 sk->max_transid = (u64)-1;
826 /* just a big number, doesn't matter much */
827 sk->nr_items = 4096;
829 while(1) {
830 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
831 if (ret < 0) {
832 fprintf(stderr, "ERROR: can't perform the search\n");
833 subvol[0] = '\0';
834 return NULL;
836 /* the ioctl returns the number of item it found in nr_items */
837 if (sk->nr_items == 0) {
838 break;
841 off = 0;
844 * for each item, pull the key out of the header and then
845 * read the root_ref item it contains
847 for (i = 0; i < sk->nr_items; i++) {
848 sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
849 off += sizeof(*sh);
850 if (sh->type == BTRFS_DIR_ITEM_KEY) {
851 dir_item = (struct btrfs_dir_item *)(args.buf + off);
852 name_len = dir_item->name_len;
853 name = (char *)(dir_item + 1);
856 /*add_root(&root_lookup, sh->objectid, sh->offset,
857 dir_id, name, name_len);*/
858 strncpy(dirname, name, name_len);
859 dirname[name_len] = '\0';
860 if (strcmp(dirname, "default") == 0) {
861 defaultsubvolid = dir_item->location.objectid;
862 break;
865 off += sh->len;
868 * record the mins in sk so we can make sure the
869 * next search doesn't repeat this root
871 sk->min_objectid = sh->objectid;
872 sk->min_type = sh->type;
873 sk->max_type = sh->type;
874 sk->min_offset = sh->offset;
876 if (defaultsubvolid != 0)
877 break;
878 sk->nr_items = 4096;
879 /* this iteration is done, step forward one root for the next
880 * ioctl
882 if (sk->min_objectid < (u64)-1) {
883 sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
884 sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
885 sk->max_type = BTRFS_ROOT_BACKREF_KEY;
886 sk->min_type = BTRFS_ROOT_BACKREF_KEY;
887 sk->min_offset = 0;
888 } else
889 break;
892 if (defaultsubvolid == 0) {
893 subvol[0] = '\0';
894 return NULL;
897 memset(&args, 0, sizeof(args));
899 /* search in the tree of tree roots */
900 sk->tree_id = 1;
903 * set the min and max to backref keys. The search will
904 * only send back this type of key now.
906 sk->max_type = BTRFS_ROOT_BACKREF_KEY;
907 sk->min_type = BTRFS_ROOT_BACKREF_KEY;
910 * set all the other params to the max, we'll take any objectid
911 * and any trans
913 sk->max_objectid = (u64)-1;
914 sk->max_offset = (u64)-1;
915 sk->max_transid = (u64)-1;
917 /* just a big number, doesn't matter much */
918 sk->nr_items = 4096;
920 while(1) {
921 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
922 if (ret < 0) {
923 fprintf(stderr, "ERROR: can't perform the search\n");
924 subvol[0] = '\0';
925 return NULL;
927 /* the ioctl returns the number of item it found in nr_items */
928 if (sk->nr_items == 0)
929 break;
931 off = 0;
934 * for each item, pull the key out of the header and then
935 * read the root_ref item it contains
937 for (i = 0; i < sk->nr_items; i++) {
938 sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
939 off += sizeof(*sh);
940 if (sh->type == BTRFS_ROOT_BACKREF_KEY) {
941 ref = (struct btrfs_root_ref *)(args.buf + off);
942 name_len = ref->name_len;
943 name = (char *)(ref + 1);
945 if (sh->objectid == defaultsubvolid) {
946 strncpy(subvol, name, name_len);
947 subvol[name_len] = '\0';
948 dprintf("The default subvolume: %s, ID: %llu\n",
949 subvol, sh->objectid);
950 break;
955 off += sh->len;
958 * record the mins in sk so we can make sure the
959 * next search doesn't repeat this root
961 sk->min_objectid = sh->objectid;
962 sk->min_type = sh->type;
963 sk->min_offset = sh->offset;
965 if (subvol[0] != '\0')
966 break;
967 sk->nr_items = 4096;
968 /* this iteration is done, step forward one root for the next
969 * ioctl
971 if (sk->min_objectid < (u64)-1) {
972 sk->min_objectid++;
973 sk->min_type = BTRFS_ROOT_BACKREF_KEY;
974 sk->min_offset = 0;
975 } else
976 break;
978 return subvol;
981 static int install_file(const char *path, int devfd, struct stat *rst)
983 if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS
984 || fs_type == UFS1 || fs_type == UFS2)
985 return ext2_fat_install_file(path, devfd, rst);
986 else if (fs_type == BTRFS)
987 return btrfs_install_file(path, devfd, rst);
988 else if (fs_type == XFS)
989 return xfs_install_file(path, devfd, rst);
991 return 1;
994 #ifdef __KLIBC__
995 static char devname_buf[64];
997 static void device_cleanup(void)
999 unlink(devname_buf);
1001 #endif
1003 /* Verify that a device fd and a pathname agree.
1004 Return 0 on valid, -1 on error. */
1005 static int validate_device_btrfs(int pathfd, int devfd);
1006 static int validate_device(const char *path, int devfd)
1008 struct stat pst, dst;
1009 struct statfs sfs;
1010 int pfd;
1011 int rv = -1;
1013 pfd = open(path, O_RDONLY|O_DIRECTORY);
1014 if (pfd < 0)
1015 goto err;
1017 if (fstat(pfd, &pst) || fstat(devfd, &dst) || statfs(path, &sfs))
1018 goto err;
1020 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
1021 if (fs_type == BTRFS) {
1022 if (sfs.f_type == BTRFS_SUPER_MAGIC)
1023 rv = validate_device_btrfs(pfd, devfd);
1024 } else {
1025 rv = (pst.st_dev == dst.st_rdev) ? 0 : -1;
1028 err:
1029 if (pfd >= 0)
1030 close(pfd);
1031 return rv;
1034 #ifndef __KLIBC__
1035 static const char *find_device(const char *mtab_file, dev_t dev)
1037 struct mntent *mnt;
1038 struct stat dst;
1039 FILE *mtab;
1040 const char *devname = NULL;
1041 bool done;
1043 mtab = setmntent(mtab_file, "r");
1044 if (!mtab)
1045 return NULL;
1047 done = false;
1048 while ((mnt = getmntent(mtab))) {
1049 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
1050 switch (fs_type) {
1051 case BTRFS:
1052 if (!strcmp(mnt->mnt_type, "btrfs") &&
1053 !stat(mnt->mnt_dir, &dst) &&
1054 dst.st_dev == dev) {
1055 if (!subvol[0])
1056 get_default_subvol(mnt->mnt_dir, subvol);
1057 done = true;
1059 break;
1060 case EXT2:
1061 if ((!strcmp(mnt->mnt_type, "ext2") ||
1062 !strcmp(mnt->mnt_type, "ext3") ||
1063 !strcmp(mnt->mnt_type, "ext4")) &&
1064 !stat(mnt->mnt_fsname, &dst) &&
1065 dst.st_rdev == dev) {
1066 done = true;
1067 break;
1069 case VFAT:
1070 if ((!strcmp(mnt->mnt_type, "vfat")) &&
1071 !stat(mnt->mnt_fsname, &dst) &&
1072 dst.st_rdev == dev) {
1073 done = true;
1074 break;
1076 case NTFS:
1077 if ((!strcmp(mnt->mnt_type, "fuseblk") /* ntfs-3g */ ||
1078 !strcmp(mnt->mnt_type, "ntfs")) &&
1079 !stat(mnt->mnt_fsname, &dst) &&
1080 dst.st_rdev == dev) {
1081 done = true;
1082 break;
1085 break;
1086 case XFS:
1087 if (!strcmp(mnt->mnt_type, "xfs") && !stat(mnt->mnt_fsname, &dst) &&
1088 dst.st_rdev == dev) {
1089 done = true;
1090 break;
1093 break;
1094 case UFS1:
1095 case UFS2:
1096 if (!strcmp(mnt->mnt_type, "ufs") && !stat(mnt->mnt_fsname, &dst) &&
1097 dst.st_rdev == dev) {
1098 done = true;
1101 break;
1102 case NONE:
1103 break;
1106 if (done) {
1107 devname = strdup(mnt->mnt_fsname);
1108 break;
1112 endmntent(mtab);
1114 return devname;
1116 #endif
1119 * On newer Linux kernels we can use sysfs to get a backwards mapping
1120 * from device names to standard filenames
1122 static const char *find_device_sysfs(dev_t dev)
1124 char sysname[64];
1125 char linkname[PATH_MAX];
1126 ssize_t llen;
1127 char *p, *q;
1128 char *buf = NULL;
1129 struct stat st;
1131 snprintf(sysname, sizeof sysname, "/sys/dev/block/%u:%u",
1132 major(dev), minor(dev));
1134 llen = readlink(sysname, linkname, sizeof linkname);
1135 if (llen < 0 || llen >= sizeof linkname)
1136 goto err;
1138 linkname[llen] = '\0';
1140 p = strrchr(linkname, '/');
1141 p = p ? p+1 : linkname; /* Leave basename */
1143 buf = q = malloc(strlen(p) + 6);
1144 if (!buf)
1145 goto err;
1147 memcpy(q, "/dev/", 5);
1148 q += 5;
1150 while (*p) {
1151 *q++ = (*p == '!') ? '/' : *p;
1152 p++;
1155 *q = '\0';
1157 if (!stat(buf, &st) && st.st_dev == dev)
1158 return buf; /* Found it! */
1160 err:
1161 if (buf)
1162 free(buf);
1163 return NULL;
1166 static const char *find_device_mountinfo(const char *path, dev_t dev)
1168 const struct mountinfo *m;
1169 struct stat st;
1171 m = find_mount(path, NULL);
1172 if (!m)
1173 return NULL;
1175 if (m->devpath[0] == '/' && m->dev == dev &&
1176 !stat(m->devpath, &st) && S_ISBLK(st.st_mode) && st.st_rdev == dev)
1177 return m->devpath;
1178 else
1179 return NULL;
1182 static int validate_device_btrfs(int pfd, int dfd)
1184 struct btrfs_ioctl_fs_info_args fsinfo;
1185 static struct btrfs_ioctl_dev_info_args devinfo;
1186 struct btrfs_super_block sb2;
1188 if (ioctl(pfd, BTRFS_IOC_FS_INFO, &fsinfo))
1189 return -1;
1191 /* We do not support multi-device btrfs yet */
1192 if (fsinfo.num_devices != 1)
1193 return -1;
1195 /* The one device will have the max devid */
1196 memset(&devinfo, 0, sizeof devinfo);
1197 devinfo.devid = fsinfo.max_id;
1198 if (ioctl(pfd, BTRFS_IOC_DEV_INFO, &devinfo))
1199 return -1;
1201 if (devinfo.path[0] != '/')
1202 return -1;
1204 if (xpread(dfd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET) != sizeof sb2)
1205 return -1;
1207 if (memcmp(sb2.magic, BTRFS_MAGIC, BTRFS_MAGIC_L))
1208 return -1;
1210 if (memcmp(sb2.fsid, fsinfo.fsid, sizeof fsinfo.fsid))
1211 return -1;
1213 if (sb2.num_devices != 1)
1214 return -1;
1216 if (sb2.dev_item.devid != devinfo.devid)
1217 return -1;
1219 if (memcmp(sb2.dev_item.uuid, devinfo.uuid, sizeof devinfo.uuid))
1220 return -1;
1222 if (memcmp(sb2.dev_item.fsid, fsinfo.fsid, sizeof fsinfo.fsid))
1223 return -1;
1225 return 0; /* It's good! */
1228 static const char *find_device_btrfs(const char *path)
1230 int pfd, dfd;
1231 struct btrfs_ioctl_fs_info_args fsinfo;
1232 static struct btrfs_ioctl_dev_info_args devinfo;
1233 const char *rv = NULL;
1235 pfd = dfd = -1;
1237 pfd = open(path, O_RDONLY);
1238 if (pfd < 0)
1239 goto err;
1241 if (ioctl(pfd, BTRFS_IOC_FS_INFO, &fsinfo))
1242 goto err;
1244 /* We do not support multi-device btrfs yet */
1245 if (fsinfo.num_devices != 1)
1246 goto err;
1248 /* The one device will have the max devid */
1249 memset(&devinfo, 0, sizeof devinfo);
1250 devinfo.devid = fsinfo.max_id;
1251 if (ioctl(pfd, BTRFS_IOC_DEV_INFO, &devinfo))
1252 goto err;
1254 if (devinfo.path[0] != '/')
1255 goto err;
1257 dfd = open((const char *)devinfo.path, O_RDONLY);
1258 if (dfd < 0)
1259 goto err;
1261 if (!validate_device_btrfs(pfd, dfd))
1262 rv = (const char *)devinfo.path; /* It's good! */
1264 err:
1265 if (pfd >= 0)
1266 close(pfd);
1267 if (dfd >= 0)
1268 close(dfd);
1269 return rv;
1272 static const char *get_devname(const char *path)
1274 const char *devname = NULL;
1275 struct stat st;
1276 struct statfs sfs;
1278 if (stat(path, &st) || !S_ISDIR(st.st_mode)) {
1279 fprintf(stderr, "%s: Not a directory: %s\n", program, path);
1280 return devname;
1282 if (statfs(path, &sfs)) {
1283 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
1284 return devname;
1287 if (opt.device)
1288 devname = opt.device;
1290 if (!devname){
1291 if (fs_type == BTRFS) {
1292 /* For btrfs try to get the device name from btrfs itself */
1293 devname = find_device_btrfs(path);
1297 if (!devname) {
1298 devname = find_device_mountinfo(path, st.st_dev);
1301 #ifdef __KLIBC__
1302 if (!devname) {
1303 devname = find_device_sysfs(st.st_dev);
1305 if (!devname) {
1306 /* klibc doesn't have getmntent and friends; instead, just create
1307 a new device with the appropriate device type */
1308 snprintf(devname_buf, sizeof devname_buf, "/tmp/dev-%u:%u",
1309 major(st.st_dev), minor(st.st_dev));
1311 if (mknod(devname_buf, S_IFBLK | 0600, st.st_dev)) {
1312 fprintf(stderr, "%s: cannot create device %s\n", program, devname);
1313 return devname;
1316 atexit(device_cleanup); /* unlink the device node on exit */
1317 devname = devname_buf;
1320 #else
1321 if (!devname) {
1322 devname = find_device("/proc/mounts", st.st_dev);
1324 if (!devname) {
1325 /* Didn't find it in /proc/mounts, try /etc/mtab */
1326 devname = find_device("/etc/mtab", st.st_dev);
1328 if (!devname) {
1329 devname = find_device_sysfs(st.st_dev);
1331 fprintf(stderr, "%s: cannot find device for path %s\n", program, path);
1332 return devname;
1335 fprintf(stderr, "%s is device %s\n", path, devname);
1337 #endif
1338 return devname;
1341 static int open_device(const char *path, struct stat *st, const char **_devname)
1343 int devfd;
1344 const char *devname = NULL;
1345 struct statfs sfs;
1347 if (st)
1348 if (stat(path, st) || !S_ISDIR(st->st_mode)) {
1349 fprintf(stderr, "%s: Not a directory: %s\n", program, path);
1350 return -1;
1353 if (statfs(path, &sfs)) {
1354 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
1355 return -1;
1358 if (sfs.f_type == EXT2_SUPER_MAGIC)
1359 fs_type = EXT2;
1360 else if (sfs.f_type == BTRFS_SUPER_MAGIC)
1361 fs_type = BTRFS;
1362 else if (sfs.f_type == MSDOS_SUPER_MAGIC)
1363 fs_type = VFAT;
1364 else if (sfs.f_type == NTFS_SB_MAGIC ||
1365 sfs.f_type == FUSE_SUPER_MAGIC /* ntfs-3g */)
1366 fs_type = NTFS;
1367 else if (sfs.f_type == XFS_SUPER_MAGIC)
1368 fs_type = XFS;
1369 else if (sfs.f_type == UFS1_SUPER_MAGIC)
1370 fs_type = UFS1;
1371 else if (sfs.f_type == UFS2_SUPER_MAGIC)
1372 fs_type = UFS2;
1374 if (!fs_type) {
1375 fprintf(stderr,
1376 "%s: not a fat, ntfs, ext2/3/4, btrfs, xfs or"
1377 "ufs1/2 filesystem: %s\n",
1378 program, path);
1379 return -1;
1382 devfd = -1;
1383 devname = get_devname(path);
1384 if (_devname)
1385 *_devname = devname;
1387 if ((devfd = open(devname, O_RDWR | O_SYNC)) < 0) {
1388 fprintf(stderr, "%s: cannot open device %s\n", program, devname);
1389 return -1;
1392 /* Verify that the device we opened is the device intended */
1393 if (validate_device(path, devfd)) {
1394 fprintf(stderr, "%s: path %s doesn't match device %s\n",
1395 program, path, devname);
1396 close(devfd);
1397 return -1;
1399 return devfd;
1402 static int btrfs_read_adv(int devfd)
1404 if (xpread(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET)
1405 != 2 * ADV_SIZE)
1406 return -1;
1408 return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
1411 static inline int xfs_read_adv(int devfd)
1413 const size_t adv_size = 2 * ADV_SIZE;
1415 if (xpread(devfd, syslinux_adv, adv_size, boot_image_len) != adv_size)
1416 return -1;
1418 return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
1421 static int ext_read_adv(const char *path, int devfd, const char **namep)
1423 int err;
1424 const char *name;
1426 if (fs_type == BTRFS) {
1427 /* btrfs "ldlinux.sys" is in 64k blank area */
1428 return btrfs_read_adv(devfd);
1429 } else if (fs_type == XFS) {
1430 /* XFS "ldlinux.sys" is in the first 2048 bytes of the primary AG */
1431 return xfs_read_adv(devfd);
1432 } else {
1433 err = read_adv(path, name = "ldlinux.sys");
1434 if (err == 2) /* ldlinux.sys does not exist */
1435 err = read_adv(path, name = "extlinux.sys");
1436 if (namep)
1437 *namep = name;
1438 return err;
1442 static int ext_write_adv(const char *path, const char *cfg, int devfd)
1444 if (fs_type == BTRFS) { /* btrfs "ldlinux.sys" is in 64k blank area */
1445 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE,
1446 BTRFS_ADV_OFFSET) != 2 * ADV_SIZE) {
1447 perror("writing adv");
1448 return 1;
1450 return 0;
1452 return write_adv(path, cfg);
1455 static int install_loader(const char *path, int update_only)
1457 struct stat st, fst;
1458 int devfd, rv;
1459 const char *devname;
1461 devfd = open_device(path, &st, &devname);
1462 if (devfd < 0)
1463 return 1;
1465 if (update_only && !syslinux_already_installed(devfd)) {
1466 fprintf(stderr, "%s: no previous syslinux boot sector found\n",
1467 program);
1468 close(devfd);
1469 return 1;
1472 /* Read a pre-existing ADV, if already installed */
1473 if (opt.reset_adv) {
1474 syslinux_reset_adv(syslinux_adv);
1475 } else if (ext_read_adv(path, devfd, NULL) < 0) {
1476 close(devfd);
1477 return 1;
1480 if (modify_adv() < 0) {
1481 close(devfd);
1482 return 1;
1485 /* Install ldlinux.sys */
1486 if (install_file(path, devfd, &fst)) {
1487 close(devfd);
1488 return 1;
1490 if (fst.st_dev != st.st_dev) {
1491 fprintf(stderr, "%s: file system changed under us - aborting!\n",
1492 program);
1493 close(devfd);
1494 return 1;
1497 sync();
1498 rv = install_bootblock(devfd, devname);
1499 close(devfd);
1500 sync();
1502 return rv;
1506 * Modify the ADV of an existing installation
1508 int modify_existing_adv(const char *path)
1510 const char *filename;
1511 int devfd;
1513 devfd = open_device(path, NULL, NULL);
1514 if (devfd < 0)
1515 return 1;
1517 if (ext_read_adv(path, devfd, &filename) < 0) {
1518 close(devfd);
1519 return 1;
1521 if (modify_adv() < 0) {
1522 close(devfd);
1523 return 1;
1525 if (ext_write_adv(path, filename, devfd) < 0) {
1526 close(devfd);
1527 return 1;
1529 close(devfd);
1530 return 0;
1533 int main(int argc, char *argv[])
1535 parse_options(argc, argv, MODE_EXTLINUX);
1537 if (!opt.directory || opt.install_mbr || opt.activate_partition)
1538 usage(EX_USAGE, 0);
1540 if (opt.update_only == -1) {
1541 if (opt.reset_adv || opt.set_once || opt.menu_save)
1542 return modify_existing_adv(opt.directory);
1543 else
1544 usage(EX_USAGE, MODE_EXTLINUX);
1547 return install_loader(opt.directory, opt.update_only);