shuffle: syslinux_dump_movelist() only takes 1 argument
[syslinux.git] / extlinux / main.c
blobaa20e1bddf323f28c128d5010a7783bb4c0a2bb0
1 /* ----------------------------------------------------------------------- *
3 * Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
4 * Copyright 2009-2012 Intel Corporation; author: H. Peter Anvin
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
9 * Boston MA 02111-1307, USA; either version 2 of the License, or
10 * (at your option) any later version; incorporated herein by reference.
12 * ----------------------------------------------------------------------- */
15 * extlinux.c
17 * Install the syslinux boot block on an fat, ntfs, ext2/3/4, btrfs and xfs
18 * 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 "misc.h"
54 #include "../version.h"
55 #include "syslxint.h"
56 #include "syslxcom.h" /* common functions shared with extlinux and syslinux */
57 #include "syslxfs.h"
58 #include "setadv.h"
59 #include "syslxopt.h" /* unified options */
60 #include "mountinfo.h"
62 #ifdef DEBUG
63 # define dprintf printf
64 #else
65 # define dprintf(...) ((void)0)
66 #endif
68 #ifndef EXT2_SUPER_OFFSET
69 #define EXT2_SUPER_OFFSET 1024
70 #endif
72 /* Since we have unused 2048 bytes in the primary AG of an XFS partition,
73 * we will use the first 0~512 bytes starting from 2048 for the Syslinux
74 * boot sector.
76 #define XFS_BOOTSECT_OFFSET (4 << SECTOR_SHIFT)
77 #define XFS_SUPPORTED_BLOCKSIZE 4096 /* 4 KiB filesystem block size */
79 /* the btrfs partition first 64K blank area is used to store boot sector and
80 boot image, the boot sector is from 0~512, the boot image starts after */
81 #define BTRFS_BOOTSECT_AREA 65536
82 #define BTRFS_EXTLINUX_OFFSET SECTOR_SIZE
83 #define BTRFS_SUBVOL_MAX 256 /* By btrfs specification */
84 static char subvol[BTRFS_SUBVOL_MAX];
86 #define BTRFS_ADV_OFFSET (BTRFS_BOOTSECT_AREA - 2 * ADV_SIZE)
89 * Get the size of a block device
91 static uint64_t get_size(int devfd)
93 uint64_t bytes;
94 uint32_t sects;
95 struct stat st;
97 #ifdef BLKGETSIZE64
98 if (!ioctl(devfd, BLKGETSIZE64, &bytes))
99 return bytes;
100 #endif
101 if (!ioctl(devfd, BLKGETSIZE, &sects))
102 return (uint64_t) sects << 9;
103 else if (!fstat(devfd, &st) && st.st_size)
104 return st.st_size;
105 else
106 return 0;
110 * Get device geometry and partition offset
112 struct geometry_table {
113 uint64_t bytes;
114 struct hd_geometry g;
117 static int sysfs_get_offset(int devfd, unsigned long *start)
119 struct stat st;
120 char sysfs_name[128];
121 FILE *f;
122 int rv;
124 if (fstat(devfd, &st))
125 return -1;
127 if ((size_t)snprintf(sysfs_name, sizeof sysfs_name,
128 "/sys/dev/block/%u:%u/start",
129 major(st.st_rdev), minor(st.st_rdev))
130 >= sizeof sysfs_name)
131 return -1;
133 f = fopen(sysfs_name, "r");
134 if (!f)
135 return -1;
137 rv = fscanf(f, "%lu", start);
138 fclose(f);
140 return (rv == 1) ? 0 : -1;
143 /* Standard floppy disk geometries, plus LS-120. Zipdisk geometry
144 (x/64/32) is the final fallback. I don't know what LS-240 has
145 as its geometry, since I don't have one and don't know anyone that does,
146 and Google wasn't helpful... */
147 static const struct geometry_table standard_geometries[] = {
148 {360 * 1024, {2, 9, 40, 0}},
149 {720 * 1024, {2, 9, 80, 0}},
150 {1200 * 1024, {2, 15, 80, 0}},
151 {1440 * 1024, {2, 18, 80, 0}},
152 {1680 * 1024, {2, 21, 80, 0}},
153 {1722 * 1024, {2, 21, 80, 0}},
154 {2880 * 1024, {2, 36, 80, 0}},
155 {3840 * 1024, {2, 48, 80, 0}},
156 {123264 * 1024, {8, 32, 963, 0}}, /* LS120 */
157 {0, {0, 0, 0, 0}}
160 int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo)
162 struct floppy_struct fd_str;
163 struct loop_info li;
164 struct loop_info64 li64;
165 const struct geometry_table *gp;
166 int rv = 0;
168 memset(geo, 0, sizeof *geo);
170 if (!ioctl(devfd, HDIO_GETGEO, geo)) {
171 goto ok;
172 } else if (!ioctl(devfd, FDGETPRM, &fd_str)) {
173 geo->heads = fd_str.head;
174 geo->sectors = fd_str.sect;
175 geo->cylinders = fd_str.track;
176 geo->start = 0;
177 goto ok;
180 /* Didn't work. Let's see if this is one of the standard geometries */
181 for (gp = standard_geometries; gp->bytes; gp++) {
182 if (gp->bytes == totalbytes) {
183 memcpy(geo, &gp->g, sizeof *geo);
184 goto ok;
188 /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is
189 what zipdisks use, so this would help if someone has a USB key that
190 they're booting in USB-ZIP mode. */
192 geo->heads = opt.heads ? : 64;
193 geo->sectors = opt.sectors ? : 32;
194 geo->cylinders = totalbytes / (geo->heads * geo->sectors << SECTOR_SHIFT);
195 geo->start = 0;
197 if (!opt.sectors && !opt.heads) {
198 fprintf(stderr,
199 "Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n"
200 " (on hard disks, this is usually harmless.)\n",
201 geo->heads, geo->sectors);
202 rv = 1; /* Suboptimal result */
206 /* If this is a loopback device, try to set the start */
207 if (!ioctl(devfd, LOOP_GET_STATUS64, &li64))
208 geo->start = li64.lo_offset >> SECTOR_SHIFT;
209 else if (!ioctl(devfd, LOOP_GET_STATUS, &li))
210 geo->start = (unsigned int)li.lo_offset >> SECTOR_SHIFT;
211 else if (!sysfs_get_offset(devfd, &geo->start)) {
212 /* OK */
215 return rv;
219 * Query the device geometry and put it into the boot sector.
220 * Map the file and put the map in the boot sector and file.
221 * Stick the "current directory" inode number into the file.
223 * Returns the number of modified bytes in the boot file.
225 static int patch_file_and_bootblock(int fd, const char *dir, int devfd)
227 struct stat dirst, xdst;
228 struct hd_geometry geo;
229 sector_t *sectp;
230 uint64_t totalbytes, totalsectors;
231 int nsect;
232 struct fat_boot_sector *sbs;
233 char *dirpath, *subpath, *xdirpath;
234 int rv;
236 dirpath = realpath(dir, NULL);
237 if (!dirpath || stat(dir, &dirst)) {
238 perror("accessing install directory");
239 exit(255); /* This should never happen */
242 if (lstat(dirpath, &xdst) ||
243 dirst.st_ino != xdst.st_ino ||
244 dirst.st_dev != xdst.st_dev) {
245 perror("realpath returned nonsense");
246 exit(255);
249 subpath = strchr(dirpath, '\0');
250 for (;;) {
251 if (*subpath == '/') {
252 if (subpath > dirpath) {
253 *subpath = '\0';
254 xdirpath = dirpath;
255 } else {
256 xdirpath = "/";
258 if (lstat(xdirpath, &xdst) || dirst.st_dev != xdst.st_dev) {
259 subpath = strchr(subpath+1, '/');
260 if (!subpath)
261 subpath = "/"; /* It's the root of the filesystem */
262 break;
264 *subpath = '/';
267 if (subpath == dirpath)
268 break;
270 subpath--;
273 /* Now subpath should contain the path relative to the fs base */
274 dprintf("subpath = %s\n", subpath);
276 totalbytes = get_size(devfd);
277 get_geometry(devfd, totalbytes, &geo);
279 if (opt.heads)
280 geo.heads = opt.heads;
281 if (opt.sectors)
282 geo.sectors = opt.sectors;
284 /* Patch this into a fake FAT superblock. This isn't because
285 FAT is a good format in any way, it's because it lets the
286 early bootstrap share code with the FAT version. */
287 dprintf("heads = %u, sect = %u\n", geo.heads, geo.sectors);
289 sbs = (struct fat_boot_sector *)syslinux_bootsect;
291 totalsectors = totalbytes >> SECTOR_SHIFT;
292 if (totalsectors >= 65536) {
293 set_16(&sbs->bsSectors, 0);
294 } else {
295 set_16(&sbs->bsSectors, totalsectors);
297 set_32(&sbs->bsHugeSectors, totalsectors);
299 set_16(&sbs->bsBytesPerSec, SECTOR_SIZE);
300 set_16(&sbs->bsSecPerTrack, geo.sectors);
301 set_16(&sbs->bsHeads, geo.heads);
302 set_32(&sbs->bsHiddenSecs, geo.start);
304 /* Construct the boot file map */
306 dprintf("directory inode = %lu\n", (unsigned long)dirst.st_ino);
307 nsect = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
308 nsect += 2; /* Two sectors for the ADV */
309 sectp = alloca(sizeof(sector_t) * nsect);
310 if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS ||
311 fs_type == XFS) {
312 if (sectmap(fd, sectp, nsect)) {
313 perror("bmap");
314 exit(1);
316 } else if (fs_type == BTRFS) {
317 int i;
318 sector_t *sp = sectp;
320 for (i = 0; i < nsect - 2; i++)
321 *sp++ = BTRFS_EXTLINUX_OFFSET/SECTOR_SIZE + i;
322 for (i = 0; i < 2; i++)
323 *sp++ = BTRFS_ADV_OFFSET/SECTOR_SIZE + i;
326 /* Create the modified image in memory */
327 rv = syslinux_patch(sectp, nsect, opt.stupid_mode,
328 opt.raid_mode, subpath, subvol);
330 free(dirpath);
331 return rv;
335 * Install the boot block on the specified device.
336 * Must be run AFTER install_file()!
338 int install_bootblock(int fd, const char *device)
340 struct ext2_super_block sb;
341 struct btrfs_super_block sb2;
342 struct fat_boot_sector sb3;
343 struct ntfs_boot_sector sb4;
344 xfs_sb_t sb5;
345 bool ok = false;
347 if (fs_type == EXT2) {
348 if (xpread(fd, &sb, sizeof sb, EXT2_SUPER_OFFSET) != sizeof sb) {
349 perror("reading superblock");
350 return 1;
353 if (sb.s_magic == EXT2_SUPER_MAGIC)
354 ok = true;
355 } else if (fs_type == BTRFS) {
356 if (xpread(fd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET)
357 != sizeof sb2) {
358 perror("reading superblock");
359 return 1;
361 if (!memcmp(sb2.magic, BTRFS_MAGIC, BTRFS_MAGIC_L))
362 ok = true;
363 } else if (fs_type == VFAT) {
364 if (xpread(fd, &sb3, sizeof sb3, 0) != sizeof sb3) {
365 perror("reading fat superblock");
366 return 1;
369 if (fat_check_sb_fields(&sb3))
370 ok = true;
371 } else if (fs_type == NTFS) {
372 if (xpread(fd, &sb4, sizeof(sb4), 0) != sizeof(sb4)) {
373 perror("reading ntfs superblock");
374 return 1;
377 if (ntfs_check_sb_fields(&sb4))
378 ok = true;
379 } else if (fs_type == XFS) {
380 if (xpread(fd, &sb5, sizeof sb5, 0) != sizeof sb5) {
381 perror("reading xfs superblock");
382 return 1;
385 if (sb5.sb_magicnum == *(u32 *)XFS_SB_MAGIC) {
386 if (be32_to_cpu(sb5.sb_blocksize) != XFS_SUPPORTED_BLOCKSIZE) {
387 fprintf(stderr,
388 "You need to have 4 KiB filesystem block size for "
389 " being able to install Syslinux in your XFS "
390 "partition (because there is no enough space in MBR to "
391 "determine where Syslinux bootsector can be installed "
392 "regardless the filesystem block size)\n");
393 return 1;
396 ok = true;
400 if (!ok) {
401 fprintf(stderr,
402 "no fat, ntfs, ext2/3/4, btrfs or xfs superblock found on %s\n",
403 device);
404 return 1;
407 if (fs_type == VFAT) {
408 struct fat_boot_sector *sbs = (struct fat_boot_sector *)syslinux_bootsect;
409 if (xpwrite(fd, &sbs->FAT_bsHead, FAT_bsHeadLen, 0) != FAT_bsHeadLen ||
410 xpwrite(fd, &sbs->FAT_bsCode, FAT_bsCodeLen,
411 offsetof(struct fat_boot_sector, FAT_bsCode)) != FAT_bsCodeLen) {
412 perror("writing fat bootblock");
413 return 1;
415 } else if (fs_type == NTFS) {
416 struct ntfs_boot_sector *sbs =
417 (struct ntfs_boot_sector *)syslinux_bootsect;
418 if (xpwrite(fd, &sbs->NTFS_bsHead,
419 NTFS_bsHeadLen, 0) != NTFS_bsHeadLen ||
420 xpwrite(fd, &sbs->NTFS_bsCode, NTFS_bsCodeLen,
421 offsetof(struct ntfs_boot_sector,
422 NTFS_bsCode)) != NTFS_bsCodeLen) {
423 perror("writing ntfs bootblock");
424 return 1;
426 } else if (fs_type == XFS) {
427 if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len,
428 XFS_BOOTSECT_OFFSET) != syslinux_bootsect_len) {
429 perror("writing xfs bootblock");
430 return 1;
432 } else {
433 if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len, 0)
434 != syslinux_bootsect_len) {
435 perror("writing bootblock");
436 return 1;
440 return 0;
443 static int rewrite_boot_image(int devfd, const char *path, const char *filename)
445 int fd;
446 int ret;
447 int modbytes;
449 /* Let's create LDLINUX.SYS file again (if it already exists, of course) */
450 fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
451 S_IRUSR | S_IRGRP | S_IROTH);
452 if (fd < 0) {
453 perror(filename);
454 return -1;
457 /* Write boot image data into LDLINUX.SYS file */
458 ret = xpwrite(fd, boot_image, boot_image_len, 0);
459 if (ret != boot_image_len) {
460 perror("writing bootblock");
461 goto error;
464 /* Write ADV */
465 ret = xpwrite(fd, syslinux_adv, 2 * ADV_SIZE, boot_image_len);
466 if (ret != 2 * ADV_SIZE) {
467 fprintf(stderr, "%s: write failure on %s\n", program, filename);
468 goto error;
471 /* Map the file, and patch the initial sector accordingly */
472 modbytes = patch_file_and_bootblock(fd, path, devfd);
474 /* Write the patch area again - this relies on the file being overwritten
475 * in place! */
476 ret = xpwrite(fd, boot_image, modbytes, 0);
477 if (ret != modbytes) {
478 fprintf(stderr, "%s: write failure on %s\n", program, filename);
479 goto error;
482 return fd;
484 error:
485 close(fd);
487 return -1;
490 int ext2_fat_install_file(const char *path, int devfd, struct stat *rst)
492 char *file, *oldfile, *c32file;
493 int fd = -1, dirfd = -1;
494 int r1, r2, r3;
496 r1 = asprintf(&file, "%s%sldlinux.sys",
497 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
498 r2 = asprintf(&oldfile, "%s%sextlinux.sys",
499 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
500 r3 = asprintf(&c32file, "%s%sldlinux.c32",
501 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
502 if (r1 < 0 || !file || r2 < 0 || !oldfile || r3 < 0 || !c32file) {
503 perror(program);
504 return 1;
507 dirfd = open(path, O_RDONLY | O_DIRECTORY);
508 if (dirfd < 0) {
509 perror(path);
510 goto bail;
513 fd = open(file, O_RDONLY);
514 if (fd < 0) {
515 if (errno != ENOENT) {
516 perror(file);
517 goto bail;
519 } else {
520 clear_attributes(fd);
522 close(fd);
524 fd = rewrite_boot_image(devfd, path, file);
525 if (fd < 0)
526 goto bail;
528 /* Attempt to set immutable flag and remove all write access */
529 /* Only set immutable flag if file is owned by root */
530 set_attributes(fd);
532 if (fstat(fd, rst)) {
533 perror(file);
534 goto bail;
537 close(dirfd);
538 close(fd);
540 /* Look if we have the old filename */
541 fd = open(oldfile, O_RDONLY);
542 if (fd >= 0) {
543 clear_attributes(fd);
544 close(fd);
545 unlink(oldfile);
548 fd = open(c32file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
549 S_IRUSR | S_IRGRP | S_IROTH);
550 if (fd < 0) {
551 perror(c32file);
552 goto bail;
555 r3 = xpwrite(fd, syslinux_ldlinuxc32, syslinux_ldlinuxc32_len, 0);
556 if (r3 != syslinux_ldlinuxc32_len) {
557 fprintf(stderr, "%s: write failure on %s\n", program, c32file);
558 goto bail;
561 free(file);
562 free(oldfile);
563 free(c32file);
564 return 0;
566 bail:
567 if (dirfd >= 0)
568 close(dirfd);
569 if (fd >= 0)
570 close(fd);
572 free(file);
573 free(oldfile);
574 free(c32file);
575 return 1;
578 /* btrfs has to install the ldlinux.sys in the first 64K blank area, which
579 is not managered by btrfs tree, so actually this is not installed as files.
580 since the cow feature of btrfs will move the ldlinux.sys every where */
581 int btrfs_install_file(const char *path, int devfd, struct stat *rst)
583 char *file;
584 int fd, rv;
586 patch_file_and_bootblock(-1, path, devfd);
587 if (xpwrite(devfd, boot_image, boot_image_len, BTRFS_EXTLINUX_OFFSET)
588 != boot_image_len) {
589 perror("writing bootblock");
590 return 1;
592 dprintf("write boot_image to 0x%x\n", BTRFS_EXTLINUX_OFFSET);
593 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET)
594 != 2 * ADV_SIZE) {
595 perror("writing adv");
596 return 1;
598 dprintf("write adv to 0x%x\n", BTRFS_ADV_OFFSET);
599 if (stat(path, rst)) {
600 perror(path);
601 return 1;
605 * Note that we *can* install ldinux.c32 as a regular file because
606 * it doesn't need to be within the first 64K. The Syslinux core
607 * has enough smarts to search the btrfs dirs and find this file.
609 rv = asprintf(&file, "%s%sldlinux.c32",
610 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
611 if (rv < 0 || !file) {
612 perror(program);
613 return 1;
616 fd = open(file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
617 S_IRUSR | S_IRGRP | S_IROTH);
618 if (fd < 0) {
619 perror(file);
620 free(file);
621 return 1;
624 rv = xpwrite(fd, syslinux_ldlinuxc32, syslinux_ldlinuxc32_len, 0);
625 if (rv != (int)syslinux_ldlinuxc32_len) {
626 fprintf(stderr, "%s: write failure on %s\n", program, file);
627 rv = 1;
628 } else
629 rv = 0;
631 close(fd);
632 free(file);
633 return rv;
637 * Due to historical reasons (SGI IRIX's design of disk layouts), the first
638 * sector in the primary AG on XFS filesystems contains the superblock, which is
639 * a problem with bootloaders that rely on BIOSes (that load VBRs which are
640 * (located in the first sector of the partition).
642 * Thus, we need to handle this issue, otherwise Syslinux will damage the XFS's
643 * superblock.
645 static int xfs_install_file(const char *path, int devfd, struct stat *rst)
647 static char file[PATH_MAX + 1];
648 static char c32file[PATH_MAX + 1];
649 int dirfd = -1;
650 int fd = -1;
651 int retval;
653 snprintf(file, PATH_MAX + 1, "%s%sldlinux.sys", path,
654 path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
655 snprintf(c32file, PATH_MAX + 1, "%s%sldlinux.c32", path,
656 path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
658 dirfd = open(path, O_RDONLY | O_DIRECTORY);
659 if (dirfd < 0) {
660 perror(path);
661 goto bail;
664 fd = open(file, O_RDONLY);
665 if (fd < 0) {
666 if (errno != ENOENT) {
667 perror(file);
668 goto bail;
670 } else {
671 clear_attributes(fd);
674 close(fd);
676 fd = rewrite_boot_image(devfd, path, file);
677 if (fd < 0)
678 goto bail;
680 /* Attempt to set immutable flag and remove all write access */
681 /* Only set immutable flag if file is owned by root */
682 set_attributes(fd);
684 if (fstat(fd, rst)) {
685 perror(file);
686 goto bail;
689 close(dirfd);
690 close(fd);
692 dirfd = -1;
693 fd = -1;
695 fd = open(c32file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
696 S_IRUSR | S_IRGRP | S_IROTH);
697 if (fd < 0) {
698 perror(c32file);
699 goto bail;
702 retval = xpwrite(fd, syslinux_ldlinuxc32, syslinux_ldlinuxc32_len, 0);
703 if (retval != (int)syslinux_ldlinuxc32_len) {
704 fprintf(stderr, "%s: write failure on %s\n", program, file);
705 goto bail;
708 close(fd);
710 sync();
712 return 0;
714 bail:
715 if (dirfd >= 0)
716 close(dirfd);
718 if (fd >= 0)
719 close(fd);
721 return 1;
725 * * test if path is a subvolume:
726 * * this function return
727 * * 0-> path exists but it is not a subvolume
728 * * 1-> path exists and it is a subvolume
729 * * -1 -> path is unaccessible
730 * */
731 static int test_issubvolume(char *path)
734 struct stat st;
735 int res;
737 res = stat(path, &st);
738 if(res < 0 )
739 return -1;
741 return (st.st_ino == 256) && S_ISDIR(st.st_mode);
746 * Get the default subvolume of a btrfs filesystem
747 * rootdir: btrfs root dir
748 * subvol: this function will save the default subvolume name here
750 static char * get_default_subvol(char * rootdir, char * subvol)
752 struct btrfs_ioctl_search_args args;
753 struct btrfs_ioctl_search_key *sk = &args.key;
754 struct btrfs_ioctl_search_header *sh;
755 int ret, i;
756 int fd;
757 struct btrfs_root_ref *ref;
758 struct btrfs_dir_item *dir_item;
759 unsigned long off = 0;
760 int name_len;
761 char *name;
762 char dirname[4096];
763 u64 defaultsubvolid = 0;
765 ret = test_issubvolume(rootdir);
766 if (ret == 1) {
767 fd = open(rootdir, O_RDONLY);
768 if (fd < 0) {
769 fprintf(stderr, "ERROR: failed to open %s\n", rootdir);
771 ret = fd;
773 if (ret <= 0) {
774 subvol[0] = '\0';
775 return NULL;
778 memset(&args, 0, sizeof(args));
780 /* search in the tree of tree roots */
781 sk->tree_id = 1;
784 * set the min and max to backref keys. The search will
785 * only send back this type of key now.
787 sk->max_type = BTRFS_DIR_ITEM_KEY;
788 sk->min_type = BTRFS_DIR_ITEM_KEY;
791 * set all the other params to the max, we'll take any objectid
792 * and any trans
794 sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
795 sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
797 sk->max_offset = (u64)-1;
798 sk->min_offset = 0;
799 sk->max_transid = (u64)-1;
801 /* just a big number, doesn't matter much */
802 sk->nr_items = 4096;
804 while(1) {
805 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
806 if (ret < 0) {
807 fprintf(stderr, "ERROR: can't perform the search\n");
808 subvol[0] = '\0';
809 return NULL;
811 /* the ioctl returns the number of item it found in nr_items */
812 if (sk->nr_items == 0) {
813 break;
816 off = 0;
819 * for each item, pull the key out of the header and then
820 * read the root_ref item it contains
822 for (i = 0; i < sk->nr_items; i++) {
823 sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
824 off += sizeof(*sh);
825 if (sh->type == BTRFS_DIR_ITEM_KEY) {
826 dir_item = (struct btrfs_dir_item *)(args.buf + off);
827 name_len = dir_item->name_len;
828 name = (char *)(dir_item + 1);
831 /*add_root(&root_lookup, sh->objectid, sh->offset,
832 dir_id, name, name_len);*/
833 strncpy(dirname, name, name_len);
834 dirname[name_len] = '\0';
835 if (strcmp(dirname, "default") == 0) {
836 defaultsubvolid = dir_item->location.objectid;
837 break;
840 off += sh->len;
843 * record the mins in sk so we can make sure the
844 * next search doesn't repeat this root
846 sk->min_objectid = sh->objectid;
847 sk->min_type = sh->type;
848 sk->max_type = sh->type;
849 sk->min_offset = sh->offset;
851 if (defaultsubvolid != 0)
852 break;
853 sk->nr_items = 4096;
854 /* this iteration is done, step forward one root for the next
855 * ioctl
857 if (sk->min_objectid < (u64)-1) {
858 sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
859 sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
860 sk->max_type = BTRFS_ROOT_BACKREF_KEY;
861 sk->min_type = BTRFS_ROOT_BACKREF_KEY;
862 sk->min_offset = 0;
863 } else
864 break;
867 if (defaultsubvolid == 0) {
868 subvol[0] = '\0';
869 return NULL;
872 memset(&args, 0, sizeof(args));
874 /* search in the tree of tree roots */
875 sk->tree_id = 1;
878 * set the min and max to backref keys. The search will
879 * only send back this type of key now.
881 sk->max_type = BTRFS_ROOT_BACKREF_KEY;
882 sk->min_type = BTRFS_ROOT_BACKREF_KEY;
885 * set all the other params to the max, we'll take any objectid
886 * and any trans
888 sk->max_objectid = (u64)-1;
889 sk->max_offset = (u64)-1;
890 sk->max_transid = (u64)-1;
892 /* just a big number, doesn't matter much */
893 sk->nr_items = 4096;
895 while(1) {
896 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
897 if (ret < 0) {
898 fprintf(stderr, "ERROR: can't perform the search\n");
899 subvol[0] = '\0';
900 return NULL;
902 /* the ioctl returns the number of item it found in nr_items */
903 if (sk->nr_items == 0)
904 break;
906 off = 0;
909 * for each item, pull the key out of the header and then
910 * read the root_ref item it contains
912 for (i = 0; i < sk->nr_items; i++) {
913 sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
914 off += sizeof(*sh);
915 if (sh->type == BTRFS_ROOT_BACKREF_KEY) {
916 ref = (struct btrfs_root_ref *)(args.buf + off);
917 name_len = ref->name_len;
918 name = (char *)(ref + 1);
920 if (sh->objectid == defaultsubvolid) {
921 strncpy(subvol, name, name_len);
922 subvol[name_len] = '\0';
923 dprintf("The default subvolume: %s, ID: %llu\n",
924 subvol, sh->objectid);
925 break;
930 off += sh->len;
933 * record the mins in sk so we can make sure the
934 * next search doesn't repeat this root
936 sk->min_objectid = sh->objectid;
937 sk->min_type = sh->type;
938 sk->min_offset = sh->offset;
940 if (subvol[0] != '\0')
941 break;
942 sk->nr_items = 4096;
943 /* this iteration is done, step forward one root for the next
944 * ioctl
946 if (sk->min_objectid < (u64)-1) {
947 sk->min_objectid++;
948 sk->min_type = BTRFS_ROOT_BACKREF_KEY;
949 sk->min_offset = 0;
950 } else
951 break;
953 return subvol;
956 static int install_file(const char *path, int devfd, struct stat *rst)
958 if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS)
959 return ext2_fat_install_file(path, devfd, rst);
960 else if (fs_type == BTRFS)
961 return btrfs_install_file(path, devfd, rst);
962 else if (fs_type == XFS)
963 return xfs_install_file(path, devfd, rst);
965 return 1;
968 #ifdef __KLIBC__
969 static char devname_buf[64];
971 static void device_cleanup(void)
973 unlink(devname_buf);
975 #endif
977 /* Verify that a device fd and a pathname agree.
978 Return 0 on valid, -1 on error. */
979 static int validate_device_btrfs(int pathfd, int devfd);
980 static int validate_device(const char *path, int devfd)
982 struct stat pst, dst;
983 struct statfs sfs;
984 int pfd;
985 int rv = -1;
987 pfd = open(path, O_RDONLY|O_DIRECTORY);
988 if (pfd < 0)
989 goto err;
991 if (fstat(pfd, &pst) || fstat(devfd, &dst) || statfs(path, &sfs))
992 goto err;
994 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
995 if (fs_type == BTRFS) {
996 if (sfs.f_type == BTRFS_SUPER_MAGIC)
997 rv = validate_device_btrfs(pfd, devfd);
998 } else {
999 rv = (pst.st_dev == dst.st_rdev) ? 0 : -1;
1002 err:
1003 if (pfd >= 0)
1004 close(pfd);
1005 return rv;
1008 #ifndef __KLIBC__
1009 static const char *find_device(const char *mtab_file, dev_t dev)
1011 struct mntent *mnt;
1012 struct stat dst;
1013 FILE *mtab;
1014 const char *devname = NULL;
1015 bool done;
1017 mtab = setmntent(mtab_file, "r");
1018 if (!mtab)
1019 return NULL;
1021 done = false;
1022 while ((mnt = getmntent(mtab))) {
1023 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
1024 switch (fs_type) {
1025 case BTRFS:
1026 if (!strcmp(mnt->mnt_type, "btrfs") &&
1027 !stat(mnt->mnt_dir, &dst) &&
1028 dst.st_dev == dev) {
1029 if (!subvol[0])
1030 get_default_subvol(mnt->mnt_dir, subvol);
1031 done = true;
1033 break;
1034 case EXT2:
1035 if ((!strcmp(mnt->mnt_type, "ext2") ||
1036 !strcmp(mnt->mnt_type, "ext3") ||
1037 !strcmp(mnt->mnt_type, "ext4")) &&
1038 !stat(mnt->mnt_fsname, &dst) &&
1039 dst.st_rdev == dev) {
1040 done = true;
1041 break;
1043 case VFAT:
1044 if ((!strcmp(mnt->mnt_type, "vfat")) &&
1045 !stat(mnt->mnt_fsname, &dst) &&
1046 dst.st_rdev == dev) {
1047 done = true;
1048 break;
1050 case NTFS:
1051 if ((!strcmp(mnt->mnt_type, "fuseblk") /* ntfs-3g */ ||
1052 !strcmp(mnt->mnt_type, "ntfs")) &&
1053 !stat(mnt->mnt_fsname, &dst) &&
1054 dst.st_rdev == dev) {
1055 done = true;
1056 break;
1059 break;
1060 case XFS:
1061 if (!strcmp(mnt->mnt_type, "xfs") && !stat(mnt->mnt_fsname, &dst) &&
1062 dst.st_rdev == dev) {
1063 done = true;
1064 break;
1066 case NONE:
1067 break;
1070 if (done) {
1071 devname = strdup(mnt->mnt_fsname);
1072 break;
1076 endmntent(mtab);
1078 return devname;
1080 #endif
1083 * On newer Linux kernels we can use sysfs to get a backwards mapping
1084 * from device names to standard filenames
1086 static const char *find_device_sysfs(dev_t dev)
1088 char sysname[64];
1089 char linkname[PATH_MAX];
1090 ssize_t llen;
1091 char *p, *q;
1092 char *buf = NULL;
1093 struct stat st;
1095 snprintf(sysname, sizeof sysname, "/sys/dev/block/%u:%u",
1096 major(dev), minor(dev));
1098 llen = readlink(sysname, linkname, sizeof linkname);
1099 if (llen < 0 || llen >= sizeof linkname)
1100 goto err;
1102 linkname[llen] = '\0';
1104 p = strrchr(linkname, '/');
1105 p = p ? p+1 : linkname; /* Leave basename */
1107 buf = q = malloc(strlen(p) + 6);
1108 if (!buf)
1109 goto err;
1111 memcpy(q, "/dev/", 5);
1112 q += 5;
1114 while (*p) {
1115 *q++ = (*p == '!') ? '/' : *p;
1116 p++;
1119 *q = '\0';
1121 if (!stat(buf, &st) && st.st_dev == dev)
1122 return buf; /* Found it! */
1124 err:
1125 if (buf)
1126 free(buf);
1127 return NULL;
1130 static const char *find_device_mountinfo(const char *path, dev_t dev)
1132 const struct mountinfo *m;
1133 struct stat st;
1135 m = find_mount(path, NULL);
1136 if (!m)
1137 return NULL;
1139 if (m->devpath[0] == '/' && m->dev == dev &&
1140 !stat(m->devpath, &st) && S_ISBLK(st.st_mode) && st.st_rdev == dev)
1141 return m->devpath;
1142 else
1143 return NULL;
1146 static int validate_device_btrfs(int pfd, int dfd)
1148 struct btrfs_ioctl_fs_info_args fsinfo;
1149 static struct btrfs_ioctl_dev_info_args devinfo;
1150 struct btrfs_super_block sb2;
1152 if (ioctl(pfd, BTRFS_IOC_FS_INFO, &fsinfo))
1153 return -1;
1155 /* We do not support multi-device btrfs yet */
1156 if (fsinfo.num_devices != 1)
1157 return -1;
1159 /* The one device will have the max devid */
1160 memset(&devinfo, 0, sizeof devinfo);
1161 devinfo.devid = fsinfo.max_id;
1162 if (ioctl(pfd, BTRFS_IOC_DEV_INFO, &devinfo))
1163 return -1;
1165 if (devinfo.path[0] != '/')
1166 return -1;
1168 if (xpread(dfd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET) != sizeof sb2)
1169 return -1;
1171 if (memcmp(sb2.magic, BTRFS_MAGIC, BTRFS_MAGIC_L))
1172 return -1;
1174 if (memcmp(sb2.fsid, fsinfo.fsid, sizeof fsinfo.fsid))
1175 return -1;
1177 if (sb2.num_devices != 1)
1178 return -1;
1180 if (sb2.dev_item.devid != devinfo.devid)
1181 return -1;
1183 if (memcmp(sb2.dev_item.uuid, devinfo.uuid, sizeof devinfo.uuid))
1184 return -1;
1186 if (memcmp(sb2.dev_item.fsid, fsinfo.fsid, sizeof fsinfo.fsid))
1187 return -1;
1189 return 0; /* It's good! */
1192 static const char *find_device_btrfs(const char *path)
1194 int pfd, dfd;
1195 struct btrfs_ioctl_fs_info_args fsinfo;
1196 static struct btrfs_ioctl_dev_info_args devinfo;
1197 const char *rv = NULL;
1199 pfd = dfd = -1;
1201 pfd = open(path, O_RDONLY);
1202 if (pfd < 0)
1203 goto err;
1205 if (ioctl(pfd, BTRFS_IOC_FS_INFO, &fsinfo))
1206 goto err;
1208 /* We do not support multi-device btrfs yet */
1209 if (fsinfo.num_devices != 1)
1210 goto err;
1212 /* The one device will have the max devid */
1213 memset(&devinfo, 0, sizeof devinfo);
1214 devinfo.devid = fsinfo.max_id;
1215 if (ioctl(pfd, BTRFS_IOC_DEV_INFO, &devinfo))
1216 goto err;
1218 if (devinfo.path[0] != '/')
1219 goto err;
1221 dfd = open((const char *)devinfo.path, O_RDONLY);
1222 if (dfd < 0)
1223 goto err;
1225 if (!validate_device_btrfs(pfd, dfd))
1226 rv = (const char *)devinfo.path; /* It's good! */
1228 err:
1229 if (pfd >= 0)
1230 close(pfd);
1231 if (dfd >= 0)
1232 close(dfd);
1233 return rv;
1236 static const char *get_devname(const char *path)
1238 const char *devname = NULL;
1239 struct stat st;
1240 struct statfs sfs;
1242 if (stat(path, &st) || !S_ISDIR(st.st_mode)) {
1243 fprintf(stderr, "%s: Not a directory: %s\n", program, path);
1244 return devname;
1246 if (statfs(path, &sfs)) {
1247 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
1248 return devname;
1251 if (opt.device)
1252 devname = opt.device;
1254 if (!devname){
1255 if (fs_type == BTRFS) {
1256 /* For btrfs try to get the device name from btrfs itself */
1257 devname = find_device_btrfs(path);
1261 if (!devname) {
1262 devname = find_device_mountinfo(path, st.st_dev);
1265 #ifdef __KLIBC__
1266 if (!devname) {
1267 devname = find_device_sysfs(st.st_dev);
1269 if (!devname) {
1270 /* klibc doesn't have getmntent and friends; instead, just create
1271 a new device with the appropriate device type */
1272 snprintf(devname_buf, sizeof devname_buf, "/tmp/dev-%u:%u",
1273 major(st.st_dev), minor(st.st_dev));
1275 if (mknod(devname_buf, S_IFBLK | 0600, st.st_dev)) {
1276 fprintf(stderr, "%s: cannot create device %s\n", program, devname);
1277 return devname;
1280 atexit(device_cleanup); /* unlink the device node on exit */
1281 devname = devname_buf;
1284 #else
1285 if (!devname) {
1286 devname = find_device("/proc/mounts", st.st_dev);
1288 if (!devname) {
1289 /* Didn't find it in /proc/mounts, try /etc/mtab */
1290 devname = find_device("/etc/mtab", st.st_dev);
1292 if (!devname) {
1293 devname = find_device_sysfs(st.st_dev);
1295 fprintf(stderr, "%s: cannot find device for path %s\n", program, path);
1296 return devname;
1299 fprintf(stderr, "%s is device %s\n", path, devname);
1301 #endif
1302 return devname;
1305 static int open_device(const char *path, struct stat *st, const char **_devname)
1307 int devfd;
1308 const char *devname = NULL;
1309 struct statfs sfs;
1311 if (st)
1312 if (stat(path, st) || !S_ISDIR(st->st_mode)) {
1313 fprintf(stderr, "%s: Not a directory: %s\n", program, path);
1314 return -1;
1317 if (statfs(path, &sfs)) {
1318 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
1319 return -1;
1322 if (sfs.f_type == EXT2_SUPER_MAGIC)
1323 fs_type = EXT2;
1324 else if (sfs.f_type == BTRFS_SUPER_MAGIC)
1325 fs_type = BTRFS;
1326 else if (sfs.f_type == MSDOS_SUPER_MAGIC)
1327 fs_type = VFAT;
1328 else if (sfs.f_type == NTFS_SB_MAGIC ||
1329 sfs.f_type == FUSE_SUPER_MAGIC /* ntfs-3g */)
1330 fs_type = NTFS;
1331 else if (sfs.f_type == XFS_SUPER_MAGIC)
1332 fs_type = XFS;
1334 if (!fs_type) {
1335 fprintf(stderr,
1336 "%s: not a fat, ntfs, ext2/3/4, btrfs or xfs filesystem: %s\n",
1337 program, path);
1338 return -1;
1341 devfd = -1;
1342 devname = get_devname(path);
1343 if (_devname)
1344 *_devname = devname;
1346 if ((devfd = open(devname, O_RDWR | O_SYNC)) < 0) {
1347 fprintf(stderr, "%s: cannot open device %s\n", program, devname);
1348 return -1;
1351 /* Verify that the device we opened is the device intended */
1352 if (validate_device(path, devfd)) {
1353 fprintf(stderr, "%s: path %s doesn't match device %s\n",
1354 program, path, devname);
1355 close(devfd);
1356 return -1;
1358 return devfd;
1361 static int btrfs_read_adv(int devfd)
1363 if (xpread(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET)
1364 != 2 * ADV_SIZE)
1365 return -1;
1367 return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
1370 static inline int xfs_read_adv(int devfd)
1372 const size_t adv_size = 2 * ADV_SIZE;
1374 if (xpread(devfd, syslinux_adv, adv_size, boot_image_len) != adv_size)
1375 return -1;
1377 return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
1380 static int ext_read_adv(const char *path, int devfd, const char **namep)
1382 int err;
1383 const char *name;
1385 if (fs_type == BTRFS) {
1386 /* btrfs "ldlinux.sys" is in 64k blank area */
1387 return btrfs_read_adv(devfd);
1388 } else if (fs_type == XFS) {
1389 /* XFS "ldlinux.sys" is in the first 2048 bytes of the primary AG */
1390 return xfs_read_adv(devfd);
1391 } else {
1392 err = read_adv(path, name = "ldlinux.sys");
1393 if (err == 2) /* ldlinux.sys does not exist */
1394 err = read_adv(path, name = "extlinux.sys");
1395 if (namep)
1396 *namep = name;
1397 return err;
1401 static int ext_write_adv(const char *path, const char *cfg, int devfd)
1403 if (fs_type == BTRFS) { /* btrfs "ldlinux.sys" is in 64k blank area */
1404 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE,
1405 BTRFS_ADV_OFFSET) != 2 * ADV_SIZE) {
1406 perror("writing adv");
1407 return 1;
1409 return 0;
1411 return write_adv(path, cfg);
1414 static int install_loader(const char *path, int update_only)
1416 struct stat st, fst;
1417 int devfd, rv;
1418 const char *devname;
1420 devfd = open_device(path, &st, &devname);
1421 if (devfd < 0)
1422 return 1;
1424 if (update_only && !syslinux_already_installed(devfd)) {
1425 fprintf(stderr, "%s: no previous syslinux boot sector found\n",
1426 program);
1427 close(devfd);
1428 return 1;
1431 /* Read a pre-existing ADV, if already installed */
1432 if (opt.reset_adv) {
1433 syslinux_reset_adv(syslinux_adv);
1434 } else if (ext_read_adv(path, devfd, NULL) < 0) {
1435 close(devfd);
1436 return 1;
1439 if (modify_adv() < 0) {
1440 close(devfd);
1441 return 1;
1444 /* Install ldlinux.sys */
1445 if (install_file(path, devfd, &fst)) {
1446 close(devfd);
1447 return 1;
1449 if (fst.st_dev != st.st_dev) {
1450 fprintf(stderr, "%s: file system changed under us - aborting!\n",
1451 program);
1452 close(devfd);
1453 return 1;
1456 sync();
1457 rv = install_bootblock(devfd, devname);
1458 close(devfd);
1459 sync();
1461 return rv;
1465 * Modify the ADV of an existing installation
1467 int modify_existing_adv(const char *path)
1469 const char *filename;
1470 int devfd;
1472 devfd = open_device(path, NULL, NULL);
1473 if (devfd < 0)
1474 return 1;
1476 if (ext_read_adv(path, devfd, &filename) < 0) {
1477 close(devfd);
1478 return 1;
1480 if (modify_adv() < 0) {
1481 close(devfd);
1482 return 1;
1484 if (ext_write_adv(path, filename, devfd) < 0) {
1485 close(devfd);
1486 return 1;
1488 close(devfd);
1489 return 0;
1492 int main(int argc, char *argv[])
1494 parse_options(argc, argv, MODE_EXTLINUX);
1496 if (!opt.directory || opt.install_mbr || opt.activate_partition)
1497 usage(EX_USAGE, 0);
1499 if (opt.update_only == -1) {
1500 if (opt.reset_adv || opt.set_once || opt.menu_save)
1501 return modify_existing_adv(opt.directory);
1502 else
1503 usage(EX_USAGE, MODE_EXTLINUX);
1506 return install_loader(opt.directory, opt.update_only);