diff options
Diffstat (limited to 'extlinux')
-rw-r--r-- | extlinux/Makefile | 67 | ||||
-rw-r--r-- | extlinux/btrfs.h | 191 | ||||
-rw-r--r-- | extlinux/fat.h | 7 | ||||
-rw-r--r-- | extlinux/main.c | 1548 | ||||
-rw-r--r-- | extlinux/misc.h | 50 | ||||
-rw-r--r-- | extlinux/mountinfo.c | 277 | ||||
-rw-r--r-- | extlinux/mountinfo.h | 35 | ||||
-rw-r--r-- | extlinux/ntfs.h | 19 | ||||
-rw-r--r-- | extlinux/ufs.h | 26 | ||||
-rw-r--r-- | extlinux/ufs_fs.h | 307 | ||||
-rw-r--r-- | extlinux/xfs.h | 25 | ||||
-rw-r--r-- | extlinux/xfs_fs.h | 501 | ||||
-rw-r--r-- | extlinux/xfs_sb.h | 476 | ||||
-rw-r--r-- | extlinux/xfs_types.h | 135 |
14 files changed, 3664 insertions, 0 deletions
diff --git a/extlinux/Makefile b/extlinux/Makefile new file mode 100644 index 0000000..02d1db5 --- /dev/null +++ b/extlinux/Makefile @@ -0,0 +1,67 @@ +## ----------------------------------------------------------------------- +## +## Copyright 2001-2008 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +## +## Linux vfat, ntfs, ext2/ext3/ext4 and btrfs installer +## + +include $(MAKEDIR)/syslinux.mk + +OPTFLAGS = -g -Os +INCLUDES = -I$(SRC) -I$(objdir) -I$(SRC)/../libinstaller +CFLAGS = $(GCCWARN) -Wno-sign-compare -D_FILE_OFFSET_BITS=64 \ + $(OPTFLAGS) $(INCLUDES) +LDFLAGS = + +SRCS = main.c \ + mountinfo.c \ + ../libinstaller/syslxmod.c \ + ../libinstaller/syslxopt.c \ + ../libinstaller/syslxcom.c \ + ../libinstaller/setadv.c \ + ../libinstaller/advio.c \ + ../libinstaller/bootsect_bin.c \ + ../libinstaller/ldlinuxc32_bin.c \ + ../libinstaller/ldlinux_bin.c +OBJS = $(patsubst %.c,%.o,$(notdir $(SRCS))) + +.SUFFIXES: .c .o .i .s .S + +VPATH = $(SRC):$(SRC)/../libinstaller:$(OBJ)/../libinstaller + +all: installer + +tidy dist: + -rm -f *.o *.i *.s *.a .*.d *.tmp + +clean: tidy + -rm -f extlinux + +spotless: clean + -rm -f *~ + +installer: extlinux + +extlinux: $(OBJS) + $(CC) $(LDFLAGS) -o $@ $^ + +strip: + $(STRIP) extlinux + +%.o: %.c + $(CC) $(UMAKEDEPS) $(CFLAGS) -c -o $@ $< +%.i: %.c + $(CC) $(UMAKEDEPS) $(CFLAGS) -E -o $@ $< +%.s: %.c + $(CC) $(UMAKEDEPS) $(CFLAGS) -S -o $@ $< + +-include .*.d diff --git a/extlinux/btrfs.h b/extlinux/btrfs.h new file mode 100644 index 0000000..17a10be --- /dev/null +++ b/extlinux/btrfs.h @@ -0,0 +1,191 @@ +#ifndef _BTRFS_H_ +#define _BTRFS_H_ + +#include <asm/types.h> +#include <linux/ioctl.h> + +#define BTRFS_SUPER_MAGIC 0x9123683E +#define BTRFS_SUPER_INFO_OFFSET (64 * 1024) +#define BTRFS_SUPER_INFO_SIZE 4096 +#define BTRFS_MAGIC "_BHRfS_M" +#define BTRFS_MAGIC_L 8 +#define BTRFS_CSUM_SIZE 32 +#define BTRFS_FSID_SIZE 16 +#define BTRFS_UUID_SIZE 16 + +/* Fixed areas reserved for the boot loader */ +#define BTRFS_BOOT_AREA_A_OFFSET 0 +#define BTRFS_BOOT_AREA_A_SIZE BTRFS_SUPER_INFO_OFFSET +#define BTRFS_BOOT_AREA_B_OFFSET (256 * 1024) +#define BTRFS_BOOT_AREA_B_SIZE ((1024-256) * 1024) + +typedef __u64 u64; +typedef __u32 u32; +typedef __u16 u16; +typedef __u8 u8; +typedef u64 __le64; +typedef u16 __le16; + +#define BTRFS_ROOT_BACKREF_KEY 144 +#define BTRFS_ROOT_TREE_DIR_OBJECTID 6ULL +#define BTRFS_DIR_ITEM_KEY 84 + +/* + * * this is used for both forward and backward root refs + * */ +struct btrfs_root_ref { + __le64 dirid; + __le64 sequence; + __le16 name_len; +} __attribute__ ((__packed__)); + +struct btrfs_disk_key { + __le64 objectid; + u8 type; + __le64 offset; +} __attribute__ ((__packed__)); + +struct btrfs_dir_item { + struct btrfs_disk_key location; + __le64 transid; + __le16 data_len; + __le16 name_len; + u8 type; +} __attribute__ ((__packed__)); + +struct btrfs_super_block { + uint8_t csum[32]; + uint8_t fsid[16]; + uint64_t bytenr; + uint64_t flags; + uint8_t magic[8]; + uint64_t generation; + uint64_t root; + uint64_t chunk_root; + uint64_t log_root; + uint64_t log_root_transid; + uint64_t total_bytes; + uint64_t bytes_used; + uint64_t root_dir_objectid; + uint64_t num_devices; + uint32_t sectorsize; + uint32_t nodesize; + uint32_t leafsize; + uint32_t stripesize; + uint32_t sys_chunk_array_size; + uint64_t chunk_root_generation; + uint64_t compat_flags; + uint64_t compat_ro_flags; + uint64_t incompat_flags; + uint16_t csum_type; + uint8_t root_level; + uint8_t chunk_root_level; + uint8_t log_root_level; + struct btrfs_dev_item { + uint64_t devid; + uint64_t total_bytes; + uint64_t bytes_used; + uint32_t io_align; + uint32_t io_width; + uint32_t sector_size; + uint64_t type; + uint64_t generation; + uint64_t start_offset; + uint32_t dev_group; + uint8_t seek_speed; + uint8_t bandwidth; + uint8_t uuid[16]; + uint8_t fsid[16]; + } __attribute__ ((__packed__)) dev_item; + uint8_t label[256]; +} __attribute__ ((__packed__)); + +#define BTRFS_IOCTL_MAGIC 0x94 +#define BTRFS_VOL_NAME_MAX 255 +#define BTRFS_PATH_NAME_MAX 4087 + +struct btrfs_ioctl_vol_args { + __s64 fd; + char name[BTRFS_PATH_NAME_MAX + 1]; +}; + +struct btrfs_ioctl_search_key { + /* which root are we searching. 0 is the tree of tree roots */ + __u64 tree_id; + + /* keys returned will be >= min and <= max */ + __u64 min_objectid; + __u64 max_objectid; + + /* keys returned will be >= min and <= max */ + __u64 min_offset; + __u64 max_offset; + + /* max and min transids to search for */ + __u64 min_transid; + __u64 max_transid; + + /* keys returned will be >= min and <= max */ + __u32 min_type; + __u32 max_type; + + /* + * how many items did userland ask for, and how many are we + * returning + */ + __u32 nr_items; + + /* align to 64 bits */ + __u32 unused; + + /* some extra for later */ + __u64 unused1; + __u64 unused2; + __u64 unused3; + __u64 unused4; +}; + +struct btrfs_ioctl_search_header { + __u64 transid; + __u64 objectid; + __u64 offset; + __u32 type; + __u32 len; +} __attribute__((may_alias)); + +#define BTRFS_DEVICE_PATH_NAME_MAX 1024 +struct btrfs_ioctl_dev_info_args { + __u64 devid; /* in/out */ + __u8 uuid[BTRFS_UUID_SIZE]; /* in/out */ + __u64 bytes_used; /* out */ + __u64 total_bytes; /* out */ + __u64 unused[379]; /* pad to 4k */ + __u8 path[BTRFS_DEVICE_PATH_NAME_MAX]; /* out */ +}; + +struct btrfs_ioctl_fs_info_args { + __u64 max_id; /* out */ + __u64 num_devices; /* out */ + __u8 fsid[BTRFS_FSID_SIZE]; /* out */ + __u64 reserved[124]; /* pad to 1k */ +}; + +#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key)) +/* + * the buf is an array of search headers where + * each header is followed by the actual item + * the type field is expanded to 32 bits for alignment + */ +struct btrfs_ioctl_search_args { + struct btrfs_ioctl_search_key key; + char buf[BTRFS_SEARCH_ARGS_BUFSIZE]; +}; + +#define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \ + struct btrfs_ioctl_search_args) +#define BTRFS_IOC_DEV_INFO _IOWR(BTRFS_IOCTL_MAGIC, 30, \ + struct btrfs_ioctl_dev_info_args) +#define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \ + struct btrfs_ioctl_fs_info_args) + +#endif diff --git a/extlinux/fat.h b/extlinux/fat.h new file mode 100644 index 0000000..5d13402 --- /dev/null +++ b/extlinux/fat.h @@ -0,0 +1,7 @@ +#ifndef _H_FAT_ +#define _H_FAT_ + +#define MSDOS_SUPER_MAGIC 0x4d44 /* MD */ +/* The rest is defined in syslxint.h */ + +#endif diff --git a/extlinux/main.c b/extlinux/main.c new file mode 100644 index 0000000..09740bd --- /dev/null +++ b/extlinux/main.c @@ -0,0 +1,1548 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1998-2008 H. Peter Anvin - All Rights Reserved + * Copyright 2009-2014 Intel Corporation; author: H. Peter Anvin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * extlinux.c + * + * Install the syslinux boot block on an fat, ntfs, ext2/3/4, btrfs, xfs, + * and ufs1/2 filesystem. + */ + +#define _GNU_SOURCE /* Enable everything */ +#include <inttypes.h> +/* This is needed to deal with the kernel headers imported into glibc 3.3.3. */ +#include <alloca.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> +#include <dirent.h> +#ifndef __KLIBC__ +#include <mntent.h> +#endif +#include <stdbool.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <sysexits.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/vfs.h> + +#include "linuxioctl.h" + +#include "btrfs.h" +#include "fat.h" +#include "ntfs.h" +#include "xfs.h" +#include "xfs_types.h" +#include "xfs_sb.h" +#include "ufs.h" +#include "ufs_fs.h" +#include "misc.h" +#include "version.h" +#include "syslxint.h" +#include "syslxcom.h" /* common functions shared with extlinux and syslinux */ +#include "syslxfs.h" +#include "setadv.h" +#include "syslxopt.h" /* unified options */ +#include "mountinfo.h" + +#ifdef DEBUG +# define dprintf printf +#else +# define dprintf(...) ((void)0) +#endif + +#ifndef EXT2_SUPER_OFFSET +#define EXT2_SUPER_OFFSET 1024 +#endif + +/* Since we have unused 2048 bytes in the primary AG of an XFS partition, + * we will use the first 0~512 bytes starting from 2048 for the Syslinux + * boot sector. + */ +#define XFS_BOOTSECT_OFFSET (4 << SECTOR_SHIFT) +#define XFS_SUPPORTED_BLOCKSIZE 4096 /* 4 KiB filesystem block size */ + +/* + * btrfs has two discontiguous areas reserved for the boot loader. + * Use the first one (Boot Area A) for the boot sector and the ADV, + * and the second one for "ldlinux.sys". + */ +#define BTRFS_EXTLINUX_OFFSET BTRFS_BOOT_AREA_B_OFFSET +#define BTRFS_EXTLINUX_SIZE BTRFS_BOOT_AREA_B_SIZE +#define BTRFS_SUBVOL_MAX 256 /* By btrfs specification */ +static char subvol[BTRFS_SUBVOL_MAX]; + +#define BTRFS_ADV_OFFSET (BTRFS_BOOT_AREA_A_OFFSET + BTRFS_BOOT_AREA_A_SIZE \ + - 2*ADV_SIZE) + +/* + * Get the size of a block device + */ +static uint64_t get_size(int devfd) +{ + uint64_t bytes; + uint32_t sects; + struct stat st; + +#ifdef BLKGETSIZE64 + if (!ioctl(devfd, BLKGETSIZE64, &bytes)) + return bytes; +#endif + if (!ioctl(devfd, BLKGETSIZE, §s)) + return (uint64_t) sects << 9; + else if (!fstat(devfd, &st) && st.st_size) + return st.st_size; + else + return 0; +} + +/* + * Get device geometry and partition offset + */ +struct geometry_table { + uint64_t bytes; + struct hd_geometry g; +}; + +static int sysfs_get_offset(int devfd, unsigned long *start) +{ + struct stat st; + char sysfs_name[128]; + FILE *f; + int rv; + + if (fstat(devfd, &st)) + return -1; + + if ((size_t)snprintf(sysfs_name, sizeof sysfs_name, + "/sys/dev/block/%u:%u/start", + major(st.st_rdev), minor(st.st_rdev)) + >= sizeof sysfs_name) + return -1; + + f = fopen(sysfs_name, "r"); + if (!f) + return -1; + + rv = fscanf(f, "%lu", start); + fclose(f); + + return (rv == 1) ? 0 : -1; +} + +/* Standard floppy disk geometries, plus LS-120. Zipdisk geometry + (x/64/32) is the final fallback. I don't know what LS-240 has + as its geometry, since I don't have one and don't know anyone that does, + and Google wasn't helpful... */ +static const struct geometry_table standard_geometries[] = { + {360 * 1024, {2, 9, 40, 0}}, + {720 * 1024, {2, 9, 80, 0}}, + {1200 * 1024, {2, 15, 80, 0}}, + {1440 * 1024, {2, 18, 80, 0}}, + {1680 * 1024, {2, 21, 80, 0}}, + {1722 * 1024, {2, 21, 80, 0}}, + {2880 * 1024, {2, 36, 80, 0}}, + {3840 * 1024, {2, 48, 80, 0}}, + {123264 * 1024, {8, 32, 963, 0}}, /* LS120 */ + {0, {0, 0, 0, 0}} +}; + +int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo) +{ + struct floppy_struct fd_str; + struct loop_info li; + struct loop_info64 li64; + const struct geometry_table *gp; + int rv = 0; + + memset(geo, 0, sizeof *geo); + + if (!ioctl(devfd, HDIO_GETGEO, geo)) { + goto ok; + } else if (!ioctl(devfd, FDGETPRM, &fd_str)) { + geo->heads = fd_str.head; + geo->sectors = fd_str.sect; + geo->cylinders = fd_str.track; + geo->start = 0; + goto ok; + } + + /* Didn't work. Let's see if this is one of the standard geometries */ + for (gp = standard_geometries; gp->bytes; gp++) { + if (gp->bytes == totalbytes) { + memcpy(geo, &gp->g, sizeof *geo); + goto ok; + } + } + + /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is + what zipdisks use, so this would help if someone has a USB key that + they're booting in USB-ZIP mode. */ + + geo->heads = opt.heads ? : 64; + geo->sectors = opt.sectors ? : 32; + geo->cylinders = totalbytes / (geo->heads * geo->sectors << SECTOR_SHIFT); + geo->start = 0; + + if (!opt.sectors && !opt.heads) { + fprintf(stderr, + "Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n" + " (on hard disks, this is usually harmless.)\n", + geo->heads, geo->sectors); + rv = 1; /* Suboptimal result */ + } + +ok: + /* If this is a loopback device, try to set the start */ + if (!ioctl(devfd, LOOP_GET_STATUS64, &li64)) + geo->start = li64.lo_offset >> SECTOR_SHIFT; + else if (!ioctl(devfd, LOOP_GET_STATUS, &li)) + geo->start = (unsigned int)li.lo_offset >> SECTOR_SHIFT; + else if (!sysfs_get_offset(devfd, &geo->start)) { + /* OK */ + } + + return rv; +} + +/* + * Query the device geometry and put it into the boot sector. + * Map the file and put the map in the boot sector and file. + * Stick the "current directory" inode number into the file. + * + * Returns the number of modified bytes in the boot file. + */ +static int patch_file_and_bootblock(int fd, const char *dir, int devfd) +{ + struct stat dirst, xdst; + struct hd_geometry geo; + sector_t *sectp; + uint64_t totalbytes, totalsectors; + int nsect; + struct fat_boot_sector *sbs; + char *dirpath, *subpath, *xdirpath; + int rv; + + dirpath = realpath(dir, NULL); + if (!dirpath || stat(dir, &dirst)) { + perror("accessing install directory"); + exit(255); /* This should never happen */ + } + + if (lstat(dirpath, &xdst) || + dirst.st_ino != xdst.st_ino || + dirst.st_dev != xdst.st_dev) { + perror("realpath returned nonsense"); + exit(255); + } + + subpath = strchr(dirpath, '\0'); + for (;;) { + if (*subpath == '/') { + if (subpath > dirpath) { + *subpath = '\0'; + xdirpath = dirpath; + } else { + xdirpath = "/"; + } + if (lstat(xdirpath, &xdst) || dirst.st_dev != xdst.st_dev) { + subpath = strchr(subpath+1, '/'); + if (!subpath) + subpath = "/"; /* It's the root of the filesystem */ + break; + } + *subpath = '/'; + } + + if (subpath == dirpath) + break; + + subpath--; + } + + /* Now subpath should contain the path relative to the fs base */ + dprintf("subpath = %s\n", subpath); + + totalbytes = get_size(devfd); + get_geometry(devfd, totalbytes, &geo); + + if (opt.heads) + geo.heads = opt.heads; + if (opt.sectors) + geo.sectors = opt.sectors; + + /* Patch this into a fake FAT superblock. This isn't because + FAT is a good format in any way, it's because it lets the + early bootstrap share code with the FAT version. */ + dprintf("heads = %u, sect = %u\n", geo.heads, geo.sectors); + + sbs = (struct fat_boot_sector *)syslinux_bootsect; + + totalsectors = totalbytes >> SECTOR_SHIFT; + if (totalsectors >= 65536) { + set_16(&sbs->bsSectors, 0); + } else { + set_16(&sbs->bsSectors, totalsectors); + } + set_32(&sbs->bsHugeSectors, totalsectors); + + set_16(&sbs->bsBytesPerSec, SECTOR_SIZE); + set_16(&sbs->bsSecPerTrack, geo.sectors); + set_16(&sbs->bsHeads, geo.heads); + set_32(&sbs->bsHiddenSecs, geo.start); + + /* Construct the boot file map */ + + dprintf("directory inode = %lu\n", (unsigned long)dirst.st_ino); + nsect = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT; + nsect += 2; /* Two sectors for the ADV */ + sectp = alloca(sizeof(sector_t) * nsect); + if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS || + fs_type == XFS || fs_type == UFS1 || fs_type == UFS2) { + if (sectmap(fd, sectp, nsect)) { + perror("bmap"); + exit(1); + } + } else if (fs_type == BTRFS) { + int i; + sector_t *sp = sectp; + + for (i = 0; i < nsect - 2; i++) + *sp++ = BTRFS_EXTLINUX_OFFSET/SECTOR_SIZE + i; + for (i = 0; i < 2; i++) + *sp++ = BTRFS_ADV_OFFSET/SECTOR_SIZE + i; + } + + /* Create the modified image in memory */ + rv = syslinux_patch(sectp, nsect, opt.stupid_mode, + opt.raid_mode, subpath, subvol); + + free(dirpath); + return rv; +} + +/* + * Install the boot block on the specified device. + * Must be run AFTER install_file()! + */ +int install_bootblock(int fd, const char *device) +{ + struct ext2_super_block sb; + struct btrfs_super_block sb2; + struct fat_boot_sector sb3; + struct ntfs_boot_sector sb4; + xfs_sb_t sb5; + struct ufs_super_block sb6; + bool ok = false; + + if (fs_type == EXT2) { + if (xpread(fd, &sb, sizeof sb, EXT2_SUPER_OFFSET) != sizeof sb) { + perror("reading superblock"); + return 1; + } + + if (sb.s_magic == EXT2_SUPER_MAGIC) + ok = true; + } else if (fs_type == BTRFS) { + if (xpread(fd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET) + != sizeof sb2) { + perror("reading superblock"); + return 1; + } + if (!memcmp(sb2.magic, BTRFS_MAGIC, BTRFS_MAGIC_L)) + ok = true; + } else if (fs_type == VFAT) { + if (xpread(fd, &sb3, sizeof sb3, 0) != sizeof sb3) { + perror("reading fat superblock"); + return 1; + } + + if (fat_check_sb_fields(&sb3)) + ok = true; + } else if (fs_type == NTFS) { + if (xpread(fd, &sb4, sizeof(sb4), 0) != sizeof(sb4)) { + perror("reading ntfs superblock"); + return 1; + } + + if (ntfs_check_sb_fields(&sb4)) + ok = true; + } else if (fs_type == XFS) { + if (xpread(fd, &sb5, sizeof sb5, 0) != sizeof sb5) { + perror("reading xfs superblock"); + return 1; + } + + if (sb5.sb_magicnum == *(u32 *)XFS_SB_MAGIC) { + if (be32_to_cpu(sb5.sb_blocksize) != XFS_SUPPORTED_BLOCKSIZE) { + fprintf(stderr, + "You need to have 4 KiB filesystem block size for " + " being able to install Syslinux in your XFS " + "partition (because there is no enough space in MBR to " + "determine where Syslinux bootsector can be installed " + "regardless the filesystem block size)\n"); + return 1; + } + + ok = true; + } + } else if (fs_type == UFS1 || fs_type == UFS2) { + uint32_t sblock_off = (fs_type == UFS1) ? + SBLOCK_UFS1 : SBLOCK_UFS2; + uint32_t ufs_smagic = (fs_type == UFS1) ? + UFS1_SUPER_MAGIC : UFS2_SUPER_MAGIC; + + if (xpread(fd, &sb6, sizeof sb6, sblock_off) != sizeof sb6) { + perror("reading superblock"); + return 1; + } + + if (sb6.fs_magic == ufs_smagic) + ok = true; + } + + if (!ok) { + fprintf(stderr, + "no fat, ntfs, ext2/3/4, btrfs, xfs " + "or ufs1/2 superblock found on %s\n", + device); + return 1; + } + + if (fs_type == VFAT) { + struct fat_boot_sector *sbs = (struct fat_boot_sector *)syslinux_bootsect; + if (xpwrite(fd, &sbs->FAT_bsHead, FAT_bsHeadLen, 0) != FAT_bsHeadLen || + xpwrite(fd, &sbs->FAT_bsCode, FAT_bsCodeLen, + offsetof(struct fat_boot_sector, FAT_bsCode)) != FAT_bsCodeLen) { + perror("writing fat bootblock"); + return 1; + } + } else if (fs_type == NTFS) { + struct ntfs_boot_sector *sbs = + (struct ntfs_boot_sector *)syslinux_bootsect; + if (xpwrite(fd, &sbs->NTFS_bsHead, + NTFS_bsHeadLen, 0) != NTFS_bsHeadLen || + xpwrite(fd, &sbs->NTFS_bsCode, NTFS_bsCodeLen, + offsetof(struct ntfs_boot_sector, + NTFS_bsCode)) != NTFS_bsCodeLen) { + perror("writing ntfs bootblock"); + return 1; + } + } else if (fs_type == XFS) { + if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len, + XFS_BOOTSECT_OFFSET) != syslinux_bootsect_len) { + perror("writing xfs bootblock"); + return 1; + } + } else { + if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len, 0) + != syslinux_bootsect_len) { + perror("writing bootblock"); + return 1; + } + } + + return 0; +} + +static int rewrite_boot_image(int devfd, const char *path, const char *filename) +{ + int fd; + int ret; + int modbytes; + + /* Let's create LDLINUX.SYS file again (if it already exists, of course) */ + fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC, + S_IRUSR | S_IRGRP | S_IROTH); + if (fd < 0) { + perror(filename); + return -1; + } + + /* Write boot image data into LDLINUX.SYS file */ + ret = xpwrite(fd, (const char _force *)boot_image, boot_image_len, 0); + if (ret != boot_image_len) { + perror("writing bootblock"); + goto error; + } + + /* Write ADV */ + ret = xpwrite(fd, syslinux_adv, 2 * ADV_SIZE, boot_image_len); + if (ret != 2 * ADV_SIZE) { + fprintf(stderr, "%s: write failure on %s\n", program, filename); + goto error; + } + + /* Map the file, and patch the initial sector accordingly */ + modbytes = patch_file_and_bootblock(fd, path, devfd); + + /* Write the patch area again - this relies on the file being overwritten + * in place! */ + ret = xpwrite(fd, (const char _force *)boot_image, modbytes, 0); + if (ret != modbytes) { + fprintf(stderr, "%s: write failure on %s\n", program, filename); + goto error; + } + + return fd; + +error: + close(fd); + + return -1; +} + +int ext2_fat_install_file(const char *path, int devfd, struct stat *rst) +{ + char *file, *oldfile, *c32file; + int fd = -1, dirfd = -1; + int r1, r2, r3; + + r1 = asprintf(&file, "%s%sldlinux.sys", + path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/"); + r2 = asprintf(&oldfile, "%s%sextlinux.sys", + path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/"); + r3 = asprintf(&c32file, "%s%sldlinux.c32", + path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/"); + if (r1 < 0 || !file || r2 < 0 || !oldfile || r3 < 0 || !c32file) { + perror(program); + return 1; + } + + dirfd = open(path, O_RDONLY | O_DIRECTORY); + if (dirfd < 0) { + perror(path); + goto bail; + } + + fd = open(file, O_RDONLY); + if (fd < 0) { + if (errno != ENOENT) { + perror(file); + goto bail; + } + } else { + clear_attributes(fd); + } + close(fd); + + fd = rewrite_boot_image(devfd, path, file); + if (fd < 0) + goto bail; + + /* Attempt to set immutable flag and remove all write access */ + /* Only set immutable flag if file is owned by root */ + set_attributes(fd); + + if (fstat(fd, rst)) { + perror(file); + goto bail; + } + + close(dirfd); + close(fd); + + /* Look if we have the old filename */ + fd = open(oldfile, O_RDONLY); + if (fd >= 0) { + clear_attributes(fd); + close(fd); + unlink(oldfile); + } + + fd = open(c32file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC, + S_IRUSR | S_IRGRP | S_IROTH); + if (fd < 0) { + perror(c32file); + goto bail; + } + + r3 = xpwrite(fd, (const char _force *)syslinux_ldlinuxc32, + syslinux_ldlinuxc32_len, 0); + if (r3 != syslinux_ldlinuxc32_len) { + fprintf(stderr, "%s: write failure on %s\n", program, c32file); + goto bail; + } + + free(file); + free(oldfile); + free(c32file); + return 0; + +bail: + if (dirfd >= 0) + close(dirfd); + if (fd >= 0) + close(fd); + + free(file); + free(oldfile); + free(c32file); + return 1; +} + +/* btrfs has to install the ldlinux.sys in the first 64K blank area, which + is not managered by btrfs tree, so actually this is not installed as files. + since the cow feature of btrfs will move the ldlinux.sys every where */ +int btrfs_install_file(const char *path, int devfd, struct stat *rst) +{ + char *file; + int fd, rv; + + patch_file_and_bootblock(-1, path, devfd); + if (xpwrite(devfd, (const char _force *)boot_image, + boot_image_len, BTRFS_EXTLINUX_OFFSET) + != boot_image_len) { + perror("writing bootblock"); + return 1; + } + dprintf("write boot_image to 0x%x\n", BTRFS_EXTLINUX_OFFSET); + if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET) + != 2 * ADV_SIZE) { + perror("writing adv"); + return 1; + } + dprintf("write adv to 0x%x\n", BTRFS_ADV_OFFSET); + if (stat(path, rst)) { + perror(path); + return 1; + } + + /* + * Note that we *can* install ldinux.c32 as a regular file because + * it doesn't need to be within the first 64K. The Syslinux core + * has enough smarts to search the btrfs dirs and find this file. + */ + rv = asprintf(&file, "%s%sldlinux.c32", + path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/"); + if (rv < 0 || !file) { + perror(program); + return 1; + } + + fd = open(file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC, + S_IRUSR | S_IRGRP | S_IROTH); + if (fd < 0) { + perror(file); + free(file); + return 1; + } + + rv = xpwrite(fd, (const char _force *)syslinux_ldlinuxc32, + syslinux_ldlinuxc32_len, 0); + if (rv != (int)syslinux_ldlinuxc32_len) { + fprintf(stderr, "%s: write failure on %s\n", program, file); + rv = 1; + } else + rv = 0; + + close(fd); + free(file); + return rv; +} + +/* + * Due to historical reasons (SGI IRIX's design of disk layouts), the first + * sector in the primary AG on XFS filesystems contains the superblock, which is + * a problem with bootloaders that rely on BIOSes (that load VBRs which are + * (located in the first sector of the partition). + * + * Thus, we need to handle this issue, otherwise Syslinux will damage the XFS's + * superblock. + */ +static int xfs_install_file(const char *path, int devfd, struct stat *rst) +{ + static char file[PATH_MAX + 1]; + static char c32file[PATH_MAX + 1]; + int dirfd = -1; + int fd = -1; + int retval; + + snprintf(file, PATH_MAX + 1, "%s%sldlinux.sys", path, + path[0] && path[strlen(path) - 1] == '/' ? "" : "/"); + snprintf(c32file, PATH_MAX + 1, "%s%sldlinux.c32", path, + path[0] && path[strlen(path) - 1] == '/' ? "" : "/"); + + dirfd = open(path, O_RDONLY | O_DIRECTORY); + if (dirfd < 0) { + perror(path); + goto bail; + } + + fd = open(file, O_RDONLY); + if (fd < 0) { + if (errno != ENOENT) { + perror(file); + goto bail; + } + } else { + clear_attributes(fd); + } + + close(fd); + + fd = rewrite_boot_image(devfd, path, file); + if (fd < 0) + goto bail; + + /* Attempt to set immutable flag and remove all write access */ + /* Only set immutable flag if file is owned by root */ + set_attributes(fd); + + if (fstat(fd, rst)) { + perror(file); + goto bail; + } + + close(dirfd); + close(fd); + + dirfd = -1; + fd = -1; + + fd = open(c32file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC, + S_IRUSR | S_IRGRP | S_IROTH); + if (fd < 0) { + perror(c32file); + goto bail; + } + + retval = xpwrite(fd, (const char _force *)syslinux_ldlinuxc32, + syslinux_ldlinuxc32_len, 0); + if (retval != (int)syslinux_ldlinuxc32_len) { + fprintf(stderr, "%s: write failure on %s\n", program, file); + goto bail; + } + + close(fd); + + sync(); + + return 0; + +bail: + if (dirfd >= 0) + close(dirfd); + + if (fd >= 0) + close(fd); + + return 1; +} + +/* + * * test if path is a subvolume: + * * this function return + * * 0-> path exists but it is not a subvolume + * * 1-> path exists and it is a subvolume + * * -1 -> path is unaccessible + * */ +static int test_issubvolume(char *path) +{ + + struct stat st; + int res; + + res = stat(path, &st); + if(res < 0 ) + return -1; + + return (st.st_ino == 256) && S_ISDIR(st.st_mode); + +} + +/* + * Get the default subvolume of a btrfs filesystem + * rootdir: btrfs root dir + * subvol: this function will save the default subvolume name here + */ +static char * get_default_subvol(char * rootdir, char * subvol) +{ + struct btrfs_ioctl_search_args args; + struct btrfs_ioctl_search_key *sk = &args.key; + struct btrfs_ioctl_search_header *sh; + int ret, i; + int fd; + struct btrfs_root_ref *ref; + struct btrfs_dir_item *dir_item; + unsigned long off = 0; + int name_len; + char *name; + char dirname[4096]; + u64 defaultsubvolid = 0; + + ret = test_issubvolume(rootdir); + if (ret == 1) { + fd = open(rootdir, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "ERROR: failed to open %s\n", rootdir); + } + ret = fd; + } + if (ret <= 0) { + subvol[0] = '\0'; + return NULL; + } + + memset(&args, 0, sizeof(args)); + + /* search in the tree of tree roots */ + sk->tree_id = 1; + + /* + * set the min and max to backref keys. The search will + * only send back this type of key now. + */ + sk->max_type = BTRFS_DIR_ITEM_KEY; + sk->min_type = BTRFS_DIR_ITEM_KEY; + + /* + * set all the other params to the max, we'll take any objectid + * and any trans + */ + sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID; + sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID; + + sk->max_offset = (u64)-1; + sk->min_offset = 0; + sk->max_transid = (u64)-1; + + /* just a big number, doesn't matter much */ + sk->nr_items = 4096; + + while(1) { + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); + if (ret < 0) { + fprintf(stderr, "ERROR: can't perform the search\n"); + subvol[0] = '\0'; + return NULL; + } + /* the ioctl returns the number of item it found in nr_items */ + if (sk->nr_items == 0) { + break; + } + + off = 0; + + /* + * for each item, pull the key out of the header and then + * read the root_ref item it contains + */ + for (i = 0; i < sk->nr_items; i++) { + sh = (struct btrfs_ioctl_search_header *)(args.buf + off); + off += sizeof(*sh); + if (sh->type == BTRFS_DIR_ITEM_KEY) { + dir_item = (struct btrfs_dir_item *)(args.buf + off); + name_len = dir_item->name_len; + name = (char *)(dir_item + 1); + + + /*add_root(&root_lookup, sh->objectid, sh->offset, + dir_id, name, name_len);*/ + strncpy(dirname, name, name_len); + dirname[name_len] = '\0'; + if (strcmp(dirname, "default") == 0) { + defaultsubvolid = dir_item->location.objectid; + break; + } + } + off += sh->len; + + /* + * record the mins in sk so we can make sure the + * next search doesn't repeat this root + */ + sk->min_objectid = sh->objectid; + sk->min_type = sh->type; + sk->max_type = sh->type; + sk->min_offset = sh->offset; + } + if (defaultsubvolid != 0) + break; + sk->nr_items = 4096; + /* this iteration is done, step forward one root for the next + * ioctl + */ + if (sk->min_objectid < (u64)-1) { + sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID; + sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID; + sk->max_type = BTRFS_ROOT_BACKREF_KEY; + sk->min_type = BTRFS_ROOT_BACKREF_KEY; + sk->min_offset = 0; + } else + break; + } + + if (defaultsubvolid == 0) { + subvol[0] = '\0'; + return NULL; + } + + memset(&args, 0, sizeof(args)); + + /* search in the tree of tree roots */ + sk->tree_id = 1; + + /* + * set the min and max to backref keys. The search will + * only send back this type of key now. + */ + sk->max_type = BTRFS_ROOT_BACKREF_KEY; + sk->min_type = BTRFS_ROOT_BACKREF_KEY; + + /* + * set all the other params to the max, we'll take any objectid + * and any trans + */ + sk->max_objectid = (u64)-1; + sk->max_offset = (u64)-1; + sk->max_transid = (u64)-1; + + /* just a big number, doesn't matter much */ + sk->nr_items = 4096; + + while(1) { + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); + if (ret < 0) { + fprintf(stderr, "ERROR: can't perform the search\n"); + subvol[0] = '\0'; + return NULL; + } + /* the ioctl returns the number of item it found in nr_items */ + if (sk->nr_items == 0) + break; + + off = 0; + + /* + * for each item, pull the key out of the header and then + * read the root_ref item it contains + */ + for (i = 0; i < sk->nr_items; i++) { + sh = (struct btrfs_ioctl_search_header *)(args.buf + off); + off += sizeof(*sh); + if (sh->type == BTRFS_ROOT_BACKREF_KEY) { + ref = (struct btrfs_root_ref *)(args.buf + off); + name_len = ref->name_len; + name = (char *)(ref + 1); + + if (sh->objectid == defaultsubvolid) { + strncpy(subvol, name, name_len); + subvol[name_len] = '\0'; + dprintf("The default subvolume: %s, ID: %llu\n", + subvol, sh->objectid); + break; + } + + } + + off += sh->len; + + /* + * record the mins in sk so we can make sure the + * next search doesn't repeat this root + */ + sk->min_objectid = sh->objectid; + sk->min_type = sh->type; + sk->min_offset = sh->offset; + } + if (subvol[0] != '\0') + break; + sk->nr_items = 4096; + /* this iteration is done, step forward one root for the next + * ioctl + */ + if (sk->min_objectid < (u64)-1) { + sk->min_objectid++; + sk->min_type = BTRFS_ROOT_BACKREF_KEY; + sk->min_offset = 0; + } else + break; + } + return subvol; +} + +static int install_file(const char *path, int devfd, struct stat *rst) +{ + if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS + || fs_type == UFS1 || fs_type == UFS2) + return ext2_fat_install_file(path, devfd, rst); + else if (fs_type == BTRFS) + return btrfs_install_file(path, devfd, rst); + else if (fs_type == XFS) + return xfs_install_file(path, devfd, rst); + + return 1; +} + +#ifdef __KLIBC__ +static char devname_buf[64]; + +static void device_cleanup(void) +{ + unlink(devname_buf); +} +#endif + +/* Verify that a device fd and a pathname agree. + Return 0 on valid, -1 on error. */ +static int validate_device_btrfs(int pathfd, int devfd); +static int validate_device(const char *path, int devfd) +{ + struct stat pst, dst; + struct statfs sfs; + int pfd; + int rv = -1; + + pfd = open(path, O_RDONLY|O_DIRECTORY); + if (pfd < 0) + goto err; + + if (fstat(pfd, &pst) || fstat(devfd, &dst) || statfs(path, &sfs)) + goto err; + + /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */ + if (fs_type == BTRFS) { + if (sfs.f_type == BTRFS_SUPER_MAGIC) + rv = validate_device_btrfs(pfd, devfd); + } else { + rv = (pst.st_dev == dst.st_rdev) ? 0 : -1; + } + +err: + if (pfd >= 0) + close(pfd); + return rv; +} + +#ifndef __KLIBC__ +static const char *find_device(const char *mtab_file, dev_t dev) +{ + struct mntent *mnt; + struct stat dst; + FILE *mtab; + const char *devname = NULL; + bool done; + + mtab = setmntent(mtab_file, "r"); + if (!mtab) + return NULL; + + done = false; + while ((mnt = getmntent(mtab))) { + /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */ + switch (fs_type) { + case BTRFS: + if (!strcmp(mnt->mnt_type, "btrfs") && + !stat(mnt->mnt_dir, &dst) && + dst.st_dev == dev) { + if (!subvol[0]) + get_default_subvol(mnt->mnt_dir, subvol); + done = true; + } + break; + case EXT2: + if ((!strcmp(mnt->mnt_type, "ext2") || + !strcmp(mnt->mnt_type, "ext3") || + !strcmp(mnt->mnt_type, "ext4")) && + !stat(mnt->mnt_fsname, &dst) && + dst.st_rdev == dev) { + done = true; + break; + } + case VFAT: + if ((!strcmp(mnt->mnt_type, "vfat")) && + !stat(mnt->mnt_fsname, &dst) && + dst.st_rdev == dev) { + done = true; + break; + } + case NTFS: + if ((!strcmp(mnt->mnt_type, "fuseblk") /* ntfs-3g */ || + !strcmp(mnt->mnt_type, "ntfs")) && + !stat(mnt->mnt_fsname, &dst) && + dst.st_rdev == dev) { + done = true; + break; + } + + break; + case XFS: + if (!strcmp(mnt->mnt_type, "xfs") && !stat(mnt->mnt_fsname, &dst) && + dst.st_rdev == dev) { + done = true; + break; + } + + break; + case UFS1: + case UFS2: + if (!strcmp(mnt->mnt_type, "ufs") && !stat(mnt->mnt_fsname, &dst) && + dst.st_rdev == dev) { + done = true; + } + + break; + case NONE: + break; + } + + if (done) { + devname = strdup(mnt->mnt_fsname); + break; + } + } + + endmntent(mtab); + + return devname; +} +#endif + +/* + * On newer Linux kernels we can use sysfs to get a backwards mapping + * from device names to standard filenames + */ +static const char *find_device_sysfs(dev_t dev) +{ + char sysname[64]; + char linkname[PATH_MAX]; + ssize_t llen; + char *p, *q; + char *buf = NULL; + struct stat st; + + snprintf(sysname, sizeof sysname, "/sys/dev/block/%u:%u", + major(dev), minor(dev)); + + llen = readlink(sysname, linkname, sizeof linkname); + if (llen < 0 || llen >= sizeof linkname) + goto err; + + linkname[llen] = '\0'; + + p = strrchr(linkname, '/'); + p = p ? p+1 : linkname; /* Leave basename */ + + buf = q = malloc(strlen(p) + 6); + if (!buf) + goto err; + + memcpy(q, "/dev/", 5); + q += 5; + + while (*p) { + *q++ = (*p == '!') ? '/' : *p; + p++; + } + + *q = '\0'; + + if (!stat(buf, &st) && st.st_dev == dev) + return buf; /* Found it! */ + +err: + if (buf) + free(buf); + return NULL; +} + +static const char *find_device_mountinfo(const char *path, dev_t dev) +{ + const struct mountinfo *m; + struct stat st; + + m = find_mount(path, NULL); + if (!m) + return NULL; + + if (m->devpath[0] == '/' && m->dev == dev && + !stat(m->devpath, &st) && S_ISBLK(st.st_mode) && st.st_rdev == dev) + return m->devpath; + else + return NULL; +} + +static int validate_device_btrfs(int pfd, int dfd) +{ + struct btrfs_ioctl_fs_info_args fsinfo; + static struct btrfs_ioctl_dev_info_args devinfo; + struct btrfs_super_block sb2; + + if (ioctl(pfd, BTRFS_IOC_FS_INFO, &fsinfo)) + return -1; + + /* We do not support multi-device btrfs yet */ + if (fsinfo.num_devices != 1) + return -1; + + /* The one device will have the max devid */ + memset(&devinfo, 0, sizeof devinfo); + devinfo.devid = fsinfo.max_id; + if (ioctl(pfd, BTRFS_IOC_DEV_INFO, &devinfo)) + return -1; + + if (devinfo.path[0] != '/') + return -1; + + if (xpread(dfd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET) != sizeof sb2) + return -1; + + if (memcmp(sb2.magic, BTRFS_MAGIC, BTRFS_MAGIC_L)) + return -1; + + if (memcmp(sb2.fsid, fsinfo.fsid, sizeof fsinfo.fsid)) + return -1; + + if (sb2.num_devices != 1) + return -1; + + if (sb2.dev_item.devid != devinfo.devid) + return -1; + + if (memcmp(sb2.dev_item.uuid, devinfo.uuid, sizeof devinfo.uuid)) + return -1; + + if (memcmp(sb2.dev_item.fsid, fsinfo.fsid, sizeof fsinfo.fsid)) + return -1; + + return 0; /* It's good! */ +} + +static const char *find_device_btrfs(const char *path) +{ + int pfd, dfd; + struct btrfs_ioctl_fs_info_args fsinfo; + static struct btrfs_ioctl_dev_info_args devinfo; + const char *rv = NULL; + + pfd = dfd = -1; + + pfd = open(path, O_RDONLY); + if (pfd < 0) + goto err; + + if (ioctl(pfd, BTRFS_IOC_FS_INFO, &fsinfo)) + goto err; + + /* We do not support multi-device btrfs yet */ + if (fsinfo.num_devices != 1) + goto err; + + /* The one device will have the max devid */ + memset(&devinfo, 0, sizeof devinfo); + devinfo.devid = fsinfo.max_id; + if (ioctl(pfd, BTRFS_IOC_DEV_INFO, &devinfo)) + goto err; + + if (devinfo.path[0] != '/') + goto err; + + dfd = open((const char *)devinfo.path, O_RDONLY); + if (dfd < 0) + goto err; + + if (!validate_device_btrfs(pfd, dfd)) + rv = (const char *)devinfo.path; /* It's good! */ + +err: + if (pfd >= 0) + close(pfd); + if (dfd >= 0) + close(dfd); + return rv; +} + +static const char *get_devname(const char *path) +{ + const char *devname = NULL; + struct stat st; + struct statfs sfs; + + if (stat(path, &st) || !S_ISDIR(st.st_mode)) { + fprintf(stderr, "%s: Not a directory: %s\n", program, path); + return devname; + } + if (statfs(path, &sfs)) { + fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno)); + return devname; + } + + if (opt.device) + devname = opt.device; + + if (!devname){ + if (fs_type == BTRFS) { + /* For btrfs try to get the device name from btrfs itself */ + devname = find_device_btrfs(path); + } + } + + if (!devname) { + devname = find_device_mountinfo(path, st.st_dev); + } + +#ifdef __KLIBC__ + if (!devname) { + devname = find_device_sysfs(st.st_dev); + } + if (!devname) { + /* klibc doesn't have getmntent and friends; instead, just create + a new device with the appropriate device type */ + snprintf(devname_buf, sizeof devname_buf, "/tmp/dev-%u:%u", + major(st.st_dev), minor(st.st_dev)); + + if (mknod(devname_buf, S_IFBLK | 0600, st.st_dev)) { + fprintf(stderr, "%s: cannot create device %s\n", program, devname); + return devname; + } + + atexit(device_cleanup); /* unlink the device node on exit */ + devname = devname_buf; + } + +#else + if (!devname) { + devname = find_device("/proc/mounts", st.st_dev); + } + if (!devname) { + /* Didn't find it in /proc/mounts, try /etc/mtab */ + devname = find_device("/etc/mtab", st.st_dev); + } + if (!devname) { + devname = find_device_sysfs(st.st_dev); + + fprintf(stderr, "%s: cannot find device for path %s\n", program, path); + return devname; + } + + fprintf(stderr, "%s is device %s\n", path, devname); + +#endif + return devname; +} + +static int open_device(const char *path, struct stat *st, const char **_devname) +{ + int devfd; + const char *devname = NULL; + struct statfs sfs; + + if (st) + if (stat(path, st) || !S_ISDIR(st->st_mode)) { + fprintf(stderr, "%s: Not a directory: %s\n", program, path); + return -1; + } + + if (statfs(path, &sfs)) { + fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno)); + return -1; + } + + if (sfs.f_type == EXT2_SUPER_MAGIC) + fs_type = EXT2; + else if (sfs.f_type == BTRFS_SUPER_MAGIC) + fs_type = BTRFS; + else if (sfs.f_type == MSDOS_SUPER_MAGIC) + fs_type = VFAT; + else if (sfs.f_type == NTFS_SB_MAGIC || + sfs.f_type == FUSE_SUPER_MAGIC /* ntfs-3g */) + fs_type = NTFS; + else if (sfs.f_type == XFS_SUPER_MAGIC) + fs_type = XFS; + else if (sfs.f_type == UFS1_SUPER_MAGIC) + fs_type = UFS1; + else if (sfs.f_type == UFS2_SUPER_MAGIC) + fs_type = UFS2; + + if (!fs_type) { + fprintf(stderr, + "%s: not a fat, ntfs, ext2/3/4, btrfs, xfs or" + "ufs1/2 filesystem: %s\n", + program, path); + return -1; + } + + devfd = -1; + devname = get_devname(path); + if (_devname) + *_devname = devname; + + if ((devfd = open(devname, O_RDWR | O_SYNC)) < 0) { + fprintf(stderr, "%s: cannot open device %s\n", program, devname); + return -1; + } + + /* Verify that the device we opened is the device intended */ + if (validate_device(path, devfd)) { + fprintf(stderr, "%s: path %s doesn't match device %s\n", + program, path, devname); + close(devfd); + return -1; + } + return devfd; +} + +static int btrfs_read_adv(int devfd) +{ + if (xpread(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET) + != 2 * ADV_SIZE) + return -1; + + return syslinux_validate_adv(syslinux_adv) ? 1 : 0; +} + +static inline int xfs_read_adv(int devfd) +{ + const size_t adv_size = 2 * ADV_SIZE; + + if (xpread(devfd, syslinux_adv, adv_size, boot_image_len) != adv_size) + return -1; + + return syslinux_validate_adv(syslinux_adv) ? 1 : 0; +} + +static int ext_read_adv(const char *path, int devfd, const char **namep) +{ + int err; + const char *name; + + if (fs_type == BTRFS) { + /* btrfs "ldlinux.sys" is in 64k blank area */ + return btrfs_read_adv(devfd); + } else if (fs_type == XFS) { + /* XFS "ldlinux.sys" is in the first 2048 bytes of the primary AG */ + return xfs_read_adv(devfd); + } else { + err = read_adv(path, name = "ldlinux.sys"); + if (err == 2) /* ldlinux.sys does not exist */ + err = read_adv(path, name = "extlinux.sys"); + if (namep) + *namep = name; + return err; + } +} + +static int ext_write_adv(const char *path, const char *cfg, int devfd) +{ + if (fs_type == BTRFS) { /* btrfs "ldlinux.sys" is in 64k blank area */ + if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE, + BTRFS_ADV_OFFSET) != 2 * ADV_SIZE) { + perror("writing adv"); + return 1; + } + return 0; + } + return write_adv(path, cfg); +} + +static int install_loader(const char *path, int update_only) +{ + struct stat st, fst; + int devfd, rv; + const char *devname; + + devfd = open_device(path, &st, &devname); + if (devfd < 0) + return 1; + + if (update_only && !syslinux_already_installed(devfd)) { + fprintf(stderr, "%s: no previous syslinux boot sector found\n", + program); + close(devfd); + return 1; + } + + /* Read a pre-existing ADV, if already installed */ + if (opt.reset_adv) { + syslinux_reset_adv(syslinux_adv); + } else if (ext_read_adv(path, devfd, NULL) < 0) { + close(devfd); + return 1; + } + + if (modify_adv() < 0) { + close(devfd); + return 1; + } + + /* Install ldlinux.sys */ + if (install_file(path, devfd, &fst)) { + close(devfd); + return 1; + } + if (fst.st_dev != st.st_dev) { + fprintf(stderr, "%s: file system changed under us - aborting!\n", + program); + close(devfd); + return 1; + } + + sync(); + rv = install_bootblock(devfd, devname); + close(devfd); + sync(); + + return rv; +} + +/* + * Modify the ADV of an existing installation + */ +int modify_existing_adv(const char *path) +{ + const char *filename; + int devfd; + + devfd = open_device(path, NULL, NULL); + if (devfd < 0) + return 1; + + if (ext_read_adv(path, devfd, &filename) < 0) { + close(devfd); + return 1; + } + if (modify_adv() < 0) { + close(devfd); + return 1; + } + if (ext_write_adv(path, filename, devfd) < 0) { + close(devfd); + return 1; + } + close(devfd); + return 0; +} + +int main(int argc, char *argv[]) +{ + parse_options(argc, argv, MODE_EXTLINUX); + + if (!opt.directory || opt.install_mbr || opt.activate_partition) + usage(EX_USAGE, 0); + + if (opt.update_only == -1) { + if (opt.reset_adv || opt.set_once || opt.menu_save) + return modify_existing_adv(opt.directory); + else + usage(EX_USAGE, MODE_EXTLINUX); + } + + return install_loader(opt.directory, opt.update_only); +} diff --git a/extlinux/misc.h b/extlinux/misc.h new file mode 100644 index 0000000..7f2f1b3 --- /dev/null +++ b/extlinux/misc.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef MISC_H_ +#define MISC_H_ + +/* Return a 64-bit litte-endian value from a given 64-bit big-endian one */ +static inline uint64_t be64_to_cpu(uint64_t val) +{ + return (uint64_t)((((uint64_t)val & (uint64_t)0x00000000000000ffULL) << 56) | + (((uint64_t)val & (uint64_t)0x000000000000ff00ULL) << 40) | + (((uint64_t)val & (uint64_t)0x0000000000ff0000ULL) << 24) | + (((uint64_t)val & (uint64_t)0x00000000ff000000ULL) << 8) | + (((uint64_t)val & (uint64_t)0x000000ff00000000ULL) >> 8) | + (((uint64_t)val & (uint64_t)0x0000ff0000000000ULL) >> 24) | + (((uint64_t)val & (uint64_t)0x00ff000000000000ULL) >> 40) | + (((uint64_t)val & (uint64_t)0xff00000000000000ULL) >> 56)); +} + +/* Return a 32-bit litte-endian value from a given 32-bit big-endian one */ +static inline uint32_t be32_to_cpu(uint32_t val) +{ + return (uint32_t)((((uint32_t)val & (uint32_t)0x000000ffUL) << 24) | + (((uint32_t)val & (uint32_t)0x0000ff00UL) << 8) | + (((uint32_t)val & (uint32_t)0x00ff0000UL) >> 8) | + (((uint32_t)val & (uint32_t)0xff000000UL) >> 24)); +} + +/* Return a 16-bit litte-endian value from a given 16-bit big-endian one */ +static inline uint16_t be16_to_cpu(uint16_t val) +{ + return (uint16_t)((((uint16_t)val & (uint16_t)0x00ffU) << 8) | + (((uint16_t)val & (uint16_t)0xff00U) >> 8)); +} + +#endif /* MISC_H_ */ diff --git a/extlinux/mountinfo.c b/extlinux/mountinfo.c new file mode 100644 index 0000000..2be8758 --- /dev/null +++ b/extlinux/mountinfo.c @@ -0,0 +1,277 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2012 Intel Corporation; All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston MA 02110-1301, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/sysmacros.h> +#include "mountinfo.h" + +/* + * Parse /proc/self/mountinfo + */ +static int get_string(FILE *f, char *string_buf, size_t string_len, char *ec) +{ + int ch; + char *p = string_buf; + + for (;;) { + if (!string_len) + return -2; /* String too long */ + + ch = getc(f); + if (ch == EOF) { + return -1; /* Got EOF */ + } else if (ch == ' ' || ch == '\t' || ch == '\n') { + *ec = ch; + *p = '\0'; + return p - string_buf; + } else if (ch == '\\') { + /* Should always be followed by 3 octal digits in 000..377 */ + int oc = 0; + int i; + for (i = 0; i < 3; i++) { + ch = getc(f); + if (ch < '0' || ch > '7' || (i == 0 && ch > '3')) + return -1; /* Bad escape sequence */ + oc = (oc << 3) + (ch - '0'); + } + if (!oc) + return -1; /* We can't handle \000 */ + *p++ = oc; + string_len--; + } else { + *p++ = ch; + string_len--; + } + } +} + +static void free_mountinfo(struct mountinfo *m) +{ + struct mountinfo *nx; + + while (m) { + free((char *)m->root); + free((char *)m->path); + free((char *)m->fstype); + free((char *)m->devpath); + free((char *)m->mountopt); + nx = m->next; + free(m); + m = nx; + } +} + +static struct mountinfo *head = NULL, **tail = &head; + +static void parse_mountinfo(void) +{ + FILE *f; + struct mountinfo *m, *mm; + char string_buf[PATH_MAX*8]; + int n; + char ec, *ep; + unsigned int ma, mi; + + f = fopen("/proc/self/mountinfo", "r"); + if (!f) + return; + + for (;;) { + m = malloc(sizeof(struct mountinfo)); + if (!m) + break; + memset(m, 0, sizeof *m); + + n = get_string(f, string_buf, sizeof string_buf, &ec); + if (n < 0 || ec == '\n') + break; + + m->mountid = strtoul(string_buf, &ep, 10); + if (*ep) + break; + + n = get_string(f, string_buf, sizeof string_buf, &ec); + if (n < 0 || ec == '\n') + break; + + m->parentid = strtoul(string_buf, &ep, 10); + if (*ep) + break; + + n = get_string(f, string_buf, sizeof string_buf, &ec); + if (n < 0 || ec == '\n') + break; + + if (sscanf(string_buf, "%u:%u", &ma, &mi) != 2) + break; + + m->dev = makedev(ma, mi); + + n = get_string(f, string_buf, sizeof string_buf, &ec); + if (n < 1 || ec == '\n' || string_buf[0] != '/') + break; + + m->root = strdup(string_buf); + if (!m->root) + break; + + n = get_string(f, string_buf, sizeof string_buf, &ec); + if (n < 1 || ec == '\n' || string_buf[0] != '/') + break; + + m->path = strdup(string_buf); + m->pathlen = (n == 1) ? 0 : n; /* Treat / as empty */ + + /* Skip tagged attributes */ + do { + n = get_string(f, string_buf, sizeof string_buf, &ec); + if (n < 0 || ec == '\n') + goto quit; + } while (n != 1 || string_buf[0] != '-'); + + n = get_string(f, string_buf, sizeof string_buf, &ec); + if (n < 0 || ec == '\n') + break; + + m->fstype = strdup(string_buf); + if (!m->fstype) + break; + + n = get_string(f, string_buf, sizeof string_buf, &ec); + if (n < 0 || ec == '\n') + break; + + m->devpath = strdup(string_buf); + if (!m->devpath) + break; + + n = get_string(f, string_buf, sizeof string_buf, &ec); + if (n < 0) + break; + + m->mountopt = strdup(string_buf); + if (!m->mountopt) + break; + + /* Skip any previously unknown fields */ + while (ec != '\n' && ec != EOF) + ec = getc(f); + + *tail = m; + tail = &m->next; + } +quit: + fclose(f); + free_mountinfo(m); + + /* Create parent links */ + for (m = head; m; m = m->next) { + for (mm = head; mm; mm = mm->next) { + if (m->parentid == mm->mountid) { + m->parent = mm; + if (!strcmp(m->path, mm->path)) + mm->hidden = 1; /* Hidden under another mount */ + break; + } + } + } +} + +const struct mountinfo *find_mount(const char *path, char **subpath) +{ + static int done_init; + char *real_path; + const struct mountinfo *m, *best; + struct stat st; + int len, matchlen; + + if (!done_init) { + parse_mountinfo(); + done_init = 1; + } + + if (stat(path, &st)) + return NULL; + + real_path = realpath(path, NULL); + if (!real_path) + return NULL; + + /* + * Tricky business: we need the longest matching subpath + * which isn't a parent of the same subpath. + */ + len = strlen(real_path); + matchlen = 0; + best = NULL; + for (m = head; m; m = m->next) { + if (m->hidden) + continue; /* Hidden underneath another mount */ + + if (m->pathlen > len) + continue; /* Cannot possibly match */ + + if (m->pathlen < matchlen) + continue; /* No point in testing this one */ + + if (st.st_dev == m->dev && + !memcmp(m->path, real_path, m->pathlen) && + (real_path[m->pathlen] == '/' || real_path[m->pathlen] == '\0')) { + matchlen = m->pathlen; + best = m; + } + } + + if (best && subpath) { + if (real_path[best->pathlen] == '\0') + *subpath = strdup("/"); + else + *subpath = strdup(real_path + best->pathlen); + } + + return best; +} + +#ifdef TEST + +int main(int argc, char *argv[]) +{ + int i; + const struct mountinfo *m; + char *subpath; + + parse_mountinfo(); + + for (i = 1; i < argc; i++) { + m = find_mount(argv[i], &subpath); + if (!m) { + printf("%s: %s\n", argv[i], strerror(errno)); + continue; + } + + printf("%s -> %s @ %s(%u,%u):%s %s %s\n", + argv[i], subpath, m->devpath, major(m->dev), minor(m->dev), + m->root, m->fstype, m->mountopt); + printf("Usable device: %s\n", find_device(m->dev, m->devpath)); + free(subpath); + } + + return 0; +} + +#endif diff --git a/extlinux/mountinfo.h b/extlinux/mountinfo.h new file mode 100644 index 0000000..9cbcac1 --- /dev/null +++ b/extlinux/mountinfo.h @@ -0,0 +1,35 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2012 Intel Corporation; All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston MA 02110-1301, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef SYSLINUX_MOUNTINFO_H +#define SYSLINUX_MOUNTINFO_H + +#include <sys/types.h> + +struct mountinfo { + struct mountinfo *next; + struct mountinfo *parent; + const char *root; + const char *path; + const char *fstype; + const char *devpath; + const char *mountopt; + int mountid; + int parentid; + int pathlen; + int hidden; + dev_t dev; +}; + +const struct mountinfo *find_mount(const char *path, char **subpath); + +#endif /* SYSLINUX_MOUNTINFO_H */ diff --git a/extlinux/ntfs.h b/extlinux/ntfs.h new file mode 100644 index 0000000..d907d45 --- /dev/null +++ b/extlinux/ntfs.h @@ -0,0 +1,19 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2011 Paulo Alcantara <pcacjr@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef _NTFS_H_ +#define _NTFS_H_ + +#define NTFS_SB_MAGIC 0x5346544E +#define FUSE_SUPER_MAGIC 0x65735546 + +#endif /* _NTFS_H_ */ diff --git a/extlinux/ufs.h b/extlinux/ufs.h new file mode 100644 index 0000000..d324699 --- /dev/null +++ b/extlinux/ufs.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2013 Raphael S. Carvalho <raphael.scarv@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef UFS_H_ +#define UFS_H_ + +#define UFS1_SUPER_MAGIC 0x00011954 +#define UFS2_SUPER_MAGIC 0x19540119 + +#endif /* UFS_H_ */ diff --git a/extlinux/ufs_fs.h b/extlinux/ufs_fs.h new file mode 100644 index 0000000..ff8a4e7 --- /dev/null +++ b/extlinux/ufs_fs.h @@ -0,0 +1,307 @@ +/* + * Taken from Linux kernel tree (linux/fs/ufs) + * linux/include/linux/ufs_fs.h + * + * Copyright (C) 1996 + * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) + * Laboratory for Computer Science Research Computing Facility + * Rutgers, The State University of New Jersey + * + * Copyright (c) 2013 Raphael S. Carvalho <raphael.scarv@gmail.com> + * + * Clean swab support by Fare <fare@tunes.org> + * just hope no one is using NNUUXXI on __?64 structure elements + * 64-bit clean thanks to Maciej W. Rozycki <macro@ds2.pg.gda.pl> + * + * 4.4BSD (FreeBSD) support added on February 1st 1998 by + * Niels Kristian Bech Jensen <nkbj@image.dk> partially based + * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>. + * + * NeXTstep support added on February 5th 1998 by + * Niels Kristian Bech Jensen <nkbj@image.dk>. + * + * Write support by Daniel Pirkl <daniel.pirkl@email.cz> + * + * HP/UX hfs filesystem support added by + * Martin K. Petersen <mkp@mkp.net>, August 1999 + * + * UFS2 (of FreeBSD 5.x) support added by + * Niraj Kumar <niraj17@iitbombay.org> , Jan 2004 + * + */ + +#ifndef __LINUX_UFS_FS_H +#define __LINUX_UFS_FS_H + +#include <inttypes.h> + +typedef uint64_t __fs64; +typedef uint32_t __fs32; +typedef uint16_t __fs16; + +#define UFS_BBLOCK 0 +#define UFS_BBSIZE 8192 +#define UFS_SBLOCK 8192 +#define UFS_SBSIZE 8192 + +#define UFS_SECTOR_SIZE 512 +#define UFS_SECTOR_BITS 9 +#define UFS_MAGIC 0x00011954 +#define UFS_MAGIC_BW 0x0f242697 +#define UFS2_MAGIC 0x19540119 +#define UFS_CIGAM 0x54190100 /* byteswapped MAGIC */ + +/* Copied from FreeBSD */ +/* + * Each disk drive contains some number of filesystems. + * A filesystem consists of a number of cylinder groups. + * Each cylinder group has inodes and data. + * + * A filesystem is described by its super-block, which in turn + * describes the cylinder groups. The super-block is critical + * data and is replicated in each cylinder group to protect against + * catastrophic loss. This is done at `newfs' time and the critical + * super-block data does not change, so the copies need not be + * referenced further unless disaster strikes. + * + * For filesystem fs, the offsets of the various blocks of interest + * are given in the super block as: + * [fs->fs_sblkno] Super-block + * [fs->fs_cblkno] Cylinder group block + * [fs->fs_iblkno] Inode blocks + * [fs->fs_dblkno] Data blocks + * The beginning of cylinder group cg in fs, is given by + * the ``cgbase(fs, cg)'' macro. + * + * Depending on the architecture and the media, the superblock may + * reside in any one of four places. For tiny media where every block + * counts, it is placed at the very front of the partition. Historically, + * UFS1 placed it 8K from the front to leave room for the disk label and + * a small bootstrap. For UFS2 it got moved to 64K from the front to leave + * room for the disk label and a bigger bootstrap, and for really piggy + * systems we check at 256K from the front if the first three fail. In + * all cases the size of the superblock will be SBLOCKSIZE. All values are + * given in byte-offset form, so they do not imply a sector size. The + * SBLOCKSEARCH specifies the order in which the locations should be searched. + */ +#define SBLOCK_FLOPPY 0 +#define SBLOCK_UFS1 8192 +#define SBLOCK_UFS2 65536 +#define SBLOCK_PIGGY 262144 +#define SBLOCKSIZE 8192 +#define SBLOCKSEARCH \ + { SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_FLOPPY, SBLOCK_PIGGY, -1 } + +#define UFS_MAXNAMLEN 255 +#define UFS_MAXMNTLEN 512 +#define UFS2_MAXMNTLEN 468 +#define UFS2_MAXVOLLEN 32 +#define UFS_MAXCSBUFS 31 +#define UFS_LINK_MAX 32000 +/* +#define UFS2_NOCSPTRS ((128 / sizeof(void *)) - 4) +*/ +#define UFS2_NOCSPTRS 28 + +/* + * UFS_DIR_PAD defines the directory entries boundaries + * (must be a multiple of 4) + */ +#define UFS_DIR_PAD 4 +#define UFS_DIR_ROUND (UFS_DIR_PAD - 1) +#define UFS_DIR_REC_LEN(name_len) (((name_len) + 1 + 8 + UFS_DIR_ROUND) & ~UFS_DIR_ROUND) + +struct ufs_timeval { + __fs32 tv_sec; + __fs32 tv_usec; +}; + +struct ufs_dir_entry { + __fs32 d_ino; /* inode number of this entry */ + __fs16 d_reclen; /* length of this entry */ + union { + __fs16 d_namlen; /* actual length of d_name */ + struct { + __u8 d_type; /* file type */ + __u8 d_namlen; /* length of string in d_name */ + } d_44; + } d_u; + __u8 d_name[UFS_MAXNAMLEN + 1]; /* file name */ +}; + +struct ufs_csum { + __fs32 cs_ndir; /* number of directories */ + __fs32 cs_nbfree; /* number of free blocks */ + __fs32 cs_nifree; /* number of free inodes */ + __fs32 cs_nffree; /* number of free frags */ +}; +struct ufs2_csum_total { + __fs64 cs_ndir; /* number of directories */ + __fs64 cs_nbfree; /* number of free blocks */ + __fs64 cs_nifree; /* number of free inodes */ + __fs64 cs_nffree; /* number of free frags */ + __fs64 cs_numclusters; /* number of free clusters */ + __fs64 cs_spare[3]; /* future expansion */ +}; + +struct ufs_csum_core { + __u64 cs_ndir; /* number of directories */ + __u64 cs_nbfree; /* number of free blocks */ + __u64 cs_nifree; /* number of free inodes */ + __u64 cs_nffree; /* number of free frags */ + __u64 cs_numclusters; /* number of free clusters */ +}; + +struct ufs_super_block { + union { + struct { + __fs32 fs_link; /* UNUSED */ + } fs_42; + struct { + __fs32 fs_state; /* file system state flag */ + } fs_sun; + } fs_u0; + __fs32 fs_rlink; /* UNUSED */ + __fs32 fs_sblkno; /* addr of super-block in filesys */ + __fs32 fs_cblkno; /* offset of cyl-block in filesys */ + __fs32 fs_iblkno; /* offset of inode-blocks in filesys */ + __fs32 fs_dblkno; /* offset of first data after cg */ + __fs32 fs_cgoffset; /* cylinder group offset in cylinder */ + __fs32 fs_cgmask; /* used to calc mod fs_ntrak */ + __fs32 fs_time; /* last time written -- time_t */ + __fs32 fs_size; /* number of blocks in fs */ + __fs32 fs_dsize; /* number of data blocks in fs */ + __fs32 fs_ncg; /* number of cylinder groups */ + __fs32 fs_bsize; /* size of basic blocks in fs */ + __fs32 fs_fsize; /* size of frag blocks in fs */ + __fs32 fs_frag; /* number of frags in a block in fs */ +/* these are configuration parameters */ + __fs32 fs_minfree; /* minimum percentage of free blocks */ + __fs32 fs_rotdelay; /* num of ms for optimal next block */ + __fs32 fs_rps; /* disk revolutions per second */ +/* these fields can be computed from the others */ + __fs32 fs_bmask; /* ``blkoff'' calc of blk offsets */ + __fs32 fs_fmask; /* ``fragoff'' calc of frag offsets */ + __fs32 fs_bshift; /* ``lblkno'' calc of logical blkno */ + __fs32 fs_fshift; /* ``numfrags'' calc number of frags */ +/* these are configuration parameters */ + __fs32 fs_maxcontig; /* max number of contiguous blks */ + __fs32 fs_maxbpg; /* max number of blks per cyl group */ +/* these fields can be computed from the others */ + __fs32 fs_fragshift; /* block to frag shift */ + __fs32 fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */ + __fs32 fs_sbsize; /* actual size of super block */ + __fs32 fs_csmask; /* csum block offset */ + __fs32 fs_csshift; /* csum block number */ + __fs32 fs_nindir; /* value of NINDIR */ + __fs32 fs_inopb; /* value of INOPB */ + __fs32 fs_nspf; /* value of NSPF */ +/* yet another configuration parameter */ + __fs32 fs_optim; /* optimization preference, see below */ +/* these fields are derived from the hardware */ + union { + struct { + __fs32 fs_npsect; /* # sectors/track including spares */ + } fs_sun; + struct { + __fs32 fs_state; /* file system state time stamp */ + } fs_sunx86; + } fs_u1; + __fs32 fs_interleave; /* hardware sector interleave */ + __fs32 fs_trackskew; /* sector 0 skew, per track */ +/* a unique id for this filesystem (currently unused and unmaintained) */ +/* In 4.3 Tahoe this space is used by fs_headswitch and fs_trkseek */ +/* Neither of those fields is used in the Tahoe code right now but */ +/* there could be problems if they are. */ + __fs32 fs_id[2]; /* file system id */ +/* sizes determined by number of cylinder groups and their sizes */ + __fs32 fs_csaddr; /* blk addr of cyl grp summary area */ + __fs32 fs_cssize; /* size of cyl grp summary area */ + __fs32 fs_cgsize; /* cylinder group size */ +/* these fields are derived from the hardware */ + __fs32 fs_ntrak; /* tracks per cylinder */ + __fs32 fs_nsect; /* sectors per track */ + __fs32 fs_spc; /* sectors per cylinder */ +/* this comes from the disk driver partitioning */ + __fs32 fs_ncyl; /* cylinders in file system */ +/* these fields can be computed from the others */ + __fs32 fs_cpg; /* cylinders per group */ + __fs32 fs_ipg; /* inodes per cylinder group */ + __fs32 fs_fpg; /* blocks per group * fs_frag */ +/* this data must be re-computed after crashes */ + struct ufs_csum fs_cstotal; /* cylinder summary information */ +/* these fields are cleared at mount time */ + __s8 fs_fmod; /* super block modified flag */ + __s8 fs_clean; /* file system is clean flag */ + __s8 fs_ronly; /* mounted read-only flag */ + __s8 fs_flags; + union { + struct { + __s8 fs_fsmnt[UFS_MAXMNTLEN];/* name mounted on */ + __fs32 fs_cgrotor; /* last cg searched */ + __fs32 fs_csp[UFS_MAXCSBUFS];/*list of fs_cs info buffers */ + __fs32 fs_maxcluster; + __fs32 fs_cpc; /* cyl per cycle in postbl */ + __fs16 fs_opostbl[16][8]; /* old rotation block list head */ + } fs_u1; + struct { + __s8 fs_fsmnt[UFS2_MAXMNTLEN]; /* name mounted on */ + __u8 fs_volname[UFS2_MAXVOLLEN]; /* volume name */ + __fs64 fs_swuid; /* system-wide uid */ + __fs32 fs_pad; /* due to alignment of fs_swuid */ + __fs32 fs_cgrotor; /* last cg searched */ + __fs32 fs_ocsp[UFS2_NOCSPTRS]; /*list of fs_cs info buffers */ + __fs32 fs_contigdirs;/*# of contiguously allocated dirs */ + __fs32 fs_csp; /* cg summary info buffer for fs_cs */ + __fs32 fs_maxcluster; + __fs32 fs_active;/* used by snapshots to track fs */ + __fs32 fs_old_cpc; /* cyl per cycle in postbl */ + __fs32 fs_maxbsize;/*maximum blocking factor permitted */ + __fs64 fs_sparecon64[17];/*old rotation block list head */ + __fs64 fs_sblockloc; /* byte offset of standard superblock */ + struct ufs2_csum_total fs_cstotal;/*cylinder summary information*/ + struct ufs_timeval fs_time; /* last time written */ + __fs64 fs_size; /* number of blocks in fs */ + __fs64 fs_dsize; /* number of data blocks in fs */ + __fs64 fs_csaddr; /* blk addr of cyl grp summary area */ + __fs64 fs_pendingblocks;/* blocks in process of being freed */ + __fs32 fs_pendinginodes;/*inodes in process of being freed */ + } fs_u2; + } fs_u11; + union { + struct { + __fs32 fs_sparecon[53];/* reserved for future constants */ + __fs32 fs_reclaim; + __fs32 fs_sparecon2[1]; + __fs32 fs_state; /* file system state time stamp */ + __fs32 fs_qbmask[2]; /* ~usb_bmask */ + __fs32 fs_qfmask[2]; /* ~usb_fmask */ + } fs_sun; + struct { + __fs32 fs_sparecon[53];/* reserved for future constants */ + __fs32 fs_reclaim; + __fs32 fs_sparecon2[1]; + __fs32 fs_npsect; /* # sectors/track including spares */ + __fs32 fs_qbmask[2]; /* ~usb_bmask */ + __fs32 fs_qfmask[2]; /* ~usb_fmask */ + } fs_sunx86; + struct { + __fs32 fs_sparecon[50];/* reserved for future constants */ + __fs32 fs_contigsumsize;/* size of cluster summary array */ + __fs32 fs_maxsymlinklen;/* max length of an internal symlink */ + __fs32 fs_inodefmt; /* format of on-disk inodes */ + __fs32 fs_maxfilesize[2]; /* max representable file size */ + __fs32 fs_qbmask[2]; /* ~usb_bmask */ + __fs32 fs_qfmask[2]; /* ~usb_fmask */ + __fs32 fs_state; /* file system state time stamp */ + } fs_44; + } fs_u2; + __fs32 fs_postblformat; /* format of positional layout tables */ + __fs32 fs_nrpos; /* number of rotational positions */ + __fs32 fs_postbloff; /* (__s16) rotation block list head */ + __fs32 fs_rotbloff; /* (__u8) blocks for each rotation */ + __fs32 fs_magic; /* magic number */ + __u8 fs_space[1]; /* list of blocks for each rotation */ +}; /*struct ufs_super_block*/ + +#endif diff --git a/extlinux/xfs.h b/extlinux/xfs.h new file mode 100644 index 0000000..412c266 --- /dev/null +++ b/extlinux/xfs.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef XFS_H_ +#define XFS_H_ + +#define XFS_SUPER_MAGIC 0x58465342 + +#endif /* XFS_H_ */ diff --git a/extlinux/xfs_fs.h b/extlinux/xfs_fs.h new file mode 100644 index 0000000..587820e --- /dev/null +++ b/extlinux/xfs_fs.h @@ -0,0 +1,501 @@ +/* + * Taken from Linux kernel tree (linux/fs/xfs) + * + * Copyright (c) 1995-2005 Silicon Graphics, Inc. + * All Rights Reserved. + * + * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef XFS_FS_H_ +#define XFS_FS_H_ + +/* + * SGI's XFS filesystem's major stuff (constants, structures) + */ + +/* + * Direct I/O attribute record used with XFS_IOC_DIOINFO + * d_miniosz is the min xfer size, xfer size multiple and file seek offset + * alignment. + */ +struct dioattr { + uint32_t d_mem; /* data buffer memory alignment */ + uint32_t d_miniosz; /* min xfer size */ + uint32_t d_maxiosz; /* max xfer size */ +}; + +/* + * Structure for XFS_IOC_FSGETXATTR[A] and XFS_IOC_FSSETXATTR. + */ +struct fsxattr { + uint32_t fsx_xflags; /* xflags field value (get/set) */ + uint32_t fsx_extsize; /* extsize field value (get/set)*/ + uint32_t fsx_nextents; /* nextents field value (get) */ + uint32_t fsx_projid; /* project identifier (get/set) */ + unsigned char fsx_pad[12]; +}; + +/* + * Flags for the bs_xflags/fsx_xflags field + * There should be a one-to-one correspondence between these flags and the + * XFS_DIFLAG_s. + */ +#define XFS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */ +#define XFS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */ +#define XFS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */ +#define XFS_XFLAG_APPEND 0x00000010 /* all writes append */ +#define XFS_XFLAG_SYNC 0x00000020 /* all writes synchronous */ +#define XFS_XFLAG_NOATIME 0x00000040 /* do not update access time */ +#define XFS_XFLAG_NODUMP 0x00000080 /* do not include in backups */ +#define XFS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */ +#define XFS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */ +#define XFS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */ +#define XFS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */ +#define XFS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */ +#define XFS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */ +#define XFS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */ +#define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ + +/* + * Structure for XFS_IOC_GETBMAP. + * On input, fill in bmv_offset and bmv_length of the first structure + * to indicate the area of interest in the file, and bmv_entries with + * the number of array elements given back. The first structure is + * updated on return to give the offset and length for the next call. + */ +struct getbmap { + int64_t bmv_offset; /* file offset of segment in blocks */ + int64_t bmv_block; /* starting block (64-bit daddr_t) */ + int64_t bmv_length; /* length of segment, blocks */ + int32_t bmv_count; /* # of entries in array incl. 1st */ + int32_t bmv_entries; /* # of entries filled in (output) */ +}; + +/* + * Structure for XFS_IOC_GETBMAPX. Fields bmv_offset through bmv_entries + * are used exactly as in the getbmap structure. The getbmapx structure + * has additional bmv_iflags and bmv_oflags fields. The bmv_iflags field + * is only used for the first structure. It contains input flags + * specifying XFS_IOC_GETBMAPX actions. The bmv_oflags field is filled + * in by the XFS_IOC_GETBMAPX command for each returned structure after + * the first. + */ +struct getbmapx { + int64_t bmv_offset; /* file offset of segment in blocks */ + int64_t bmv_block; /* starting block (64-bit daddr_t) */ + int64_t bmv_length; /* length of segment, blocks */ + int32_t bmv_count; /* # of entries in array incl. 1st */ + int32_t bmv_entries; /* # of entries filled in (output). */ + int32_t bmv_iflags; /* input flags (1st structure) */ + int32_t bmv_oflags; /* output flags (after 1st structure)*/ + int32_t bmv_unused1; /* future use */ + int32_t bmv_unused2; /* future use */ +}; + +/* bmv_iflags values - set by XFS_IOC_GETBMAPX caller. */ +#define BMV_IF_ATTRFORK 0x1 /* return attr fork rather than data */ +#define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */ +#define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */ +#define BMV_IF_DELALLOC 0x8 /* rtn status BMV_OF_DELALLOC if req */ +#define BMV_IF_NO_HOLES 0x10 /* Do not return holes */ +#define BMV_IF_VALID \ + (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC| \ + BMV_IF_DELALLOC|BMV_IF_NO_HOLES) + +/* bmv_oflags values - returned for each non-header segment */ +#define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */ +#define BMV_OF_DELALLOC 0x2 /* segment = delayed allocation */ +#define BMV_OF_LAST 0x4 /* segment is the last in the file */ + +/* + * Structure for XFS_IOC_FSSETDM. + * For use by backup and restore programs to set the XFS on-disk inode + * fields di_dmevmask and di_dmstate. These must be set to exactly and + * only values previously obtained via xfs_bulkstat! (Specifically the + * xfs_bstat_t fields bs_dmevmask and bs_dmstate.) + */ +struct fsdmidata { + uint32_t fsd_dmevmask; /* corresponds to di_dmevmask */ + __u16 fsd_padding; + __u16 fsd_dmstate; /* corresponds to di_dmstate */ +}; + +/* + * File segment locking set data type for 64 bit access. + * Also used for all the RESV/FREE interfaces. + */ +typedef struct xfs_flock64 { + __s16 l_type; + __s16 l_whence; + int64_t l_start; + int64_t l_len; /* len == 0 means until end of file */ + int32_t l_sysid; + uint32_t l_pid; + int32_t l_pad[4]; /* reserve area */ +} xfs_flock64_t; + +/* + * Output for XFS_IOC_FSGEOMETRY_V1 + */ +typedef struct xfs_fsop_geom_v1 { + uint32_t blocksize; /* filesystem (data) block size */ + uint32_t rtextsize; /* realtime extent size */ + uint32_t agblocks; /* fsblocks in an AG */ + uint32_t agcount; /* number of allocation groups */ + uint32_t logblocks; /* fsblocks in the log */ + uint32_t sectsize; /* (data) sector size, bytes */ + uint32_t inodesize; /* inode size in bytes */ + uint32_t imaxpct; /* max allowed inode space(%) */ + uint64_t datablocks; /* fsblocks in data subvolume */ + uint64_t rtblocks; /* fsblocks in realtime subvol */ + uint64_t rtextents; /* rt extents in realtime subvol*/ + uint64_t logstart; /* starting fsblock of the log */ + unsigned char uuid[16]; /* unique id of the filesystem */ + uint32_t sunit; /* stripe unit, fsblocks */ + uint32_t swidth; /* stripe width, fsblocks */ + int32_t version; /* structure version */ + uint32_t flags; /* superblock version flags */ + uint32_t logsectsize; /* log sector size, bytes */ + uint32_t rtsectsize; /* realtime sector size, bytes */ + uint32_t dirblocksize; /* directory block size, bytes */ +} xfs_fsop_geom_v1_t; + +/* + * Output for XFS_IOC_FSGEOMETRY + */ +typedef struct xfs_fsop_geom { + uint32_t blocksize; /* filesystem (data) block size */ + uint32_t rtextsize; /* realtime extent size */ + uint32_t agblocks; /* fsblocks in an AG */ + uint32_t agcount; /* number of allocation groups */ + uint32_t logblocks; /* fsblocks in the log */ + uint32_t sectsize; /* (data) sector size, bytes */ + uint32_t inodesize; /* inode size in bytes */ + uint32_t imaxpct; /* max allowed inode space(%) */ + uint64_t datablocks; /* fsblocks in data subvolume */ + uint64_t rtblocks; /* fsblocks in realtime subvol */ + uint64_t rtextents; /* rt extents in realtime subvol*/ + uint64_t logstart; /* starting fsblock of the log */ + unsigned char uuid[16]; /* unique id of the filesystem */ + uint32_t sunit; /* stripe unit, fsblocks */ + uint32_t swidth; /* stripe width, fsblocks */ + int32_t version; /* structure version */ + uint32_t flags; /* superblock version flags */ + uint32_t logsectsize; /* log sector size, bytes */ + uint32_t rtsectsize; /* realtime sector size, bytes */ + uint32_t dirblocksize; /* directory block size, bytes */ + uint32_t logsunit; /* log stripe unit, bytes */ +} xfs_fsop_geom_t; + +/* Output for XFS_FS_COUNTS */ +typedef struct xfs_fsop_counts { + uint64_t freedata; /* free data section blocks */ + uint64_t freertx; /* free rt extents */ + uint64_t freeino; /* free inodes */ + uint64_t allocino; /* total allocated inodes */ +} xfs_fsop_counts_t; + +/* Input/Output for XFS_GET_RESBLKS and XFS_SET_RESBLKS */ +typedef struct xfs_fsop_resblks { + uint64_t resblks; + uint64_t resblks_avail; +} xfs_fsop_resblks_t; + +#define XFS_FSOP_GEOM_VERSION 0 + +#define XFS_FSOP_GEOM_FLAGS_ATTR 0x0001 /* attributes in use */ +#define XFS_FSOP_GEOM_FLAGS_NLINK 0x0002 /* 32-bit nlink values */ +#define XFS_FSOP_GEOM_FLAGS_QUOTA 0x0004 /* quotas enabled */ +#define XFS_FSOP_GEOM_FLAGS_IALIGN 0x0008 /* inode alignment */ +#define XFS_FSOP_GEOM_FLAGS_DALIGN 0x0010 /* large data alignment */ +#define XFS_FSOP_GEOM_FLAGS_SHARED 0x0020 /* read-only shared */ +#define XFS_FSOP_GEOM_FLAGS_EXTFLG 0x0040 /* special extent flag */ +#define XFS_FSOP_GEOM_FLAGS_DIRV2 0x0080 /* directory version 2 */ +#define XFS_FSOP_GEOM_FLAGS_LOGV2 0x0100 /* log format version 2 */ +#define XFS_FSOP_GEOM_FLAGS_SECTOR 0x0200 /* sector sizes >1BB */ +#define XFS_FSOP_GEOM_FLAGS_ATTR2 0x0400 /* inline attributes rework */ +#define XFS_FSOP_GEOM_FLAGS_DIRV2CI 0x1000 /* ASCII only CI names */ +#define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */ + + +/* + * Minimum and maximum sizes need for growth checks + */ +#define XFS_MIN_AG_BLOCKS 64 +#define XFS_MIN_LOG_BLOCKS 512ULL +#define XFS_MAX_LOG_BLOCKS (1024 * 1024ULL) +#define XFS_MIN_LOG_BYTES (10 * 1024 * 1024ULL) + +/* keep the maximum size under 2^31 by a small amount */ +#define XFS_MAX_LOG_BYTES \ + ((2 * 1024 * 1024 * 1024ULL) - XFS_MIN_LOG_BYTES) + +/* Used for sanity checks on superblock */ +#define XFS_MAX_DBLOCKS(s) ((xfs_drfsbno_t)(s)->sb_agcount * (s)->sb_agblocks) +#define XFS_MIN_DBLOCKS(s) ((xfs_drfsbno_t)((s)->sb_agcount - 1) * \ + (s)->sb_agblocks + XFS_MIN_AG_BLOCKS) + +/* + * Structures for XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG & XFS_IOC_FSGROWFSRT + */ +typedef struct xfs_growfs_data { + uint64_t newblocks; /* new data subvol size, fsblocks */ + uint32_t imaxpct; /* new inode space percentage limit */ +} xfs_growfs_data_t; + +typedef struct xfs_growfs_log { + uint32_t newblocks; /* new log size, fsblocks */ + uint32_t isint; /* 1 if new log is internal */ +} xfs_growfs_log_t; + +typedef struct xfs_growfs_rt { + uint64_t newblocks; /* new realtime size, fsblocks */ + uint32_t extsize; /* new realtime extent size, fsblocks */ +} xfs_growfs_rt_t; + + +/* + * Structures returned from ioctl XFS_IOC_FSBULKSTAT & XFS_IOC_FSBULKSTAT_SINGLE + */ +typedef struct xfs_bstime { + time_t tv_sec; /* seconds */ + int32_t tv_nsec; /* and nanoseconds */ +} xfs_bstime_t; + +typedef struct xfs_bstat { + uint64_t bs_ino; /* inode number */ + __u16 bs_mode; /* type and mode */ + __u16 bs_nlink; /* number of links */ + uint32_t bs_uid; /* user id */ + uint32_t bs_gid; /* group id */ + uint32_t bs_rdev; /* device value */ + int32_t bs_blksize; /* block size */ + int64_t bs_size; /* file size */ + xfs_bstime_t bs_atime; /* access time */ + xfs_bstime_t bs_mtime; /* modify time */ + xfs_bstime_t bs_ctime; /* inode change time */ + int64_t bs_blocks; /* number of blocks */ + uint32_t bs_xflags; /* extended flags */ + int32_t bs_extsize; /* extent size */ + int32_t bs_extents; /* number of extents */ + uint32_t bs_gen; /* generation count */ + __u16 bs_projid_lo; /* lower part of project id */ +#define bs_projid bs_projid_lo /* (previously just bs_projid) */ + __u16 bs_forkoff; /* inode fork offset in bytes */ + __u16 bs_projid_hi; /* higher part of project id */ + unsigned char bs_pad[10]; /* pad space, unused */ + uint32_t bs_dmevmask; /* DMIG event mask */ + __u16 bs_dmstate; /* DMIG state info */ + __u16 bs_aextents; /* attribute number of extents */ +} xfs_bstat_t; + +/* + * The user-level BulkStat Request interface structure. + */ +typedef struct xfs_fsop_bulkreq { + uint64_t __user *lastip; /* last inode # pointer */ + int32_t icount; /* count of entries in buffer */ + void __user *ubuffer;/* user buffer for inode desc. */ + int32_t __user *ocount; /* output count pointer */ +} xfs_fsop_bulkreq_t; + + +/* + * Structures returned from xfs_inumbers routine (XFS_IOC_FSINUMBERS). + */ +typedef struct xfs_inogrp { + uint64_t xi_startino; /* starting inode number */ + int32_t xi_alloccount; /* # bits set in allocmask */ + uint64_t xi_allocmask; /* mask of allocated inodes */ +} xfs_inogrp_t; + + +/* + * Error injection. + */ +typedef struct xfs_error_injection { + int32_t fd; + int32_t errtag; +} xfs_error_injection_t; + + +/* + * The user-level Handle Request interface structure. + */ +typedef struct xfs_fsop_handlereq { + uint32_t fd; /* fd for FD_TO_HANDLE */ + void __user *path; /* user pathname */ + uint32_t oflags; /* open flags */ + void __user *ihandle;/* user supplied handle */ + uint32_t ihandlen; /* user supplied length */ + void __user *ohandle;/* user buffer for handle */ + uint32_t __user *ohandlen;/* user buffer length */ +} xfs_fsop_handlereq_t; + +/* + * Compound structures for passing args through Handle Request interfaces + * xfs_fssetdm_by_handle, xfs_attrlist_by_handle, xfs_attrmulti_by_handle + * - ioctls: XFS_IOC_FSSETDM_BY_HANDLE, XFS_IOC_ATTRLIST_BY_HANDLE, and + * XFS_IOC_ATTRMULTI_BY_HANDLE + */ + +typedef struct xfs_fsop_setdm_handlereq { + struct xfs_fsop_handlereq hreq; /* handle information */ + struct fsdmidata __user *data; /* DMAPI data */ +} xfs_fsop_setdm_handlereq_t; + +typedef struct xfs_attrlist_cursor { + uint32_t opaque[4]; +} xfs_attrlist_cursor_t; + +typedef struct xfs_fsop_attrlist_handlereq { + struct xfs_fsop_handlereq hreq; /* handle interface structure */ + struct xfs_attrlist_cursor pos; /* opaque cookie, list offset */ + uint32_t flags; /* which namespace to use */ + uint32_t buflen; /* length of buffer supplied */ + void __user *buffer; /* returned names */ +} xfs_fsop_attrlist_handlereq_t; + +typedef struct xfs_attr_multiop { + uint32_t am_opcode; +#define ATTR_OP_GET 1 /* return the indicated attr's value */ +#define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */ +#define ATTR_OP_REMOVE 3 /* remove the indicated attr */ + int32_t am_error; + void __user *am_attrname; + void __user *am_attrvalue; + uint32_t am_length; + uint32_t am_flags; +} xfs_attr_multiop_t; + +typedef struct xfs_fsop_attrmulti_handlereq { + struct xfs_fsop_handlereq hreq; /* handle interface structure */ + uint32_t opcount;/* count of following multiop */ + struct xfs_attr_multiop __user *ops; /* attr_multi data */ +} xfs_fsop_attrmulti_handlereq_t; + +/* + * per machine unique filesystem identifier types. + */ +typedef struct { uint32_t val[2]; } xfs_fsid_t; /* file system id type */ + +typedef struct xfs_fid { + __u16 fid_len; /* length of remainder */ + __u16 fid_pad; + uint32_t fid_gen; /* generation number */ + uint64_t fid_ino; /* 64 bits inode number */ +} xfs_fid_t; + +typedef struct xfs_handle { + union { + int64_t align; /* force alignment of ha_fid */ + xfs_fsid_t _ha_fsid; /* unique file system identifier */ + } ha_u; + xfs_fid_t ha_fid; /* file system specific file ID */ +} xfs_handle_t; +#define ha_fsid ha_u._ha_fsid + +#define XFS_HSIZE(handle) (((char *) &(handle).ha_fid.fid_pad \ + - (char *) &(handle)) \ + + (handle).ha_fid.fid_len) + +/* + * Flags for going down operation + */ +#define XFS_FSOP_GOING_FLAGS_DEFAULT 0x0 /* going down */ +#define XFS_FSOP_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */ +#define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */ + +/* + * ioctl commands that are used by Linux filesystems + */ +#define XFS_IOC_GETXFLAGS FS_IOC_GETFLAGS +#define XFS_IOC_SETXFLAGS FS_IOC_SETFLAGS +#define XFS_IOC_GETVERSION FS_IOC_GETVERSION + +/* + * ioctl commands that replace IRIX fcntl()'s + * For 'documentation' purposed more than anything else, + * the "cmd #" field reflects the IRIX fcntl number. + */ +#define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64) +#define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64) +#define XFS_IOC_DIOINFO _IOR ('X', 30, struct dioattr) +#define XFS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr) +#define XFS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr) +#define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64) +#define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64) +#define XFS_IOC_GETBMAP _IOWR('X', 38, struct getbmap) +#define XFS_IOC_FSSETDM _IOW ('X', 39, struct fsdmidata) +#define XFS_IOC_RESVSP _IOW ('X', 40, struct xfs_flock64) +#define XFS_IOC_UNRESVSP _IOW ('X', 41, struct xfs_flock64) +#define XFS_IOC_RESVSP64 _IOW ('X', 42, struct xfs_flock64) +#define XFS_IOC_UNRESVSP64 _IOW ('X', 43, struct xfs_flock64) +#define XFS_IOC_GETBMAPA _IOWR('X', 44, struct getbmap) +#define XFS_IOC_FSGETXATTRA _IOR ('X', 45, struct fsxattr) +/* XFS_IOC_SETBIOSIZE ---- deprecated 46 */ +/* XFS_IOC_GETBIOSIZE ---- deprecated 47 */ +#define XFS_IOC_GETBMAPX _IOWR('X', 56, struct getbmap) +#define XFS_IOC_ZERO_RANGE _IOW ('X', 57, struct xfs_flock64) + +/* + * ioctl commands that replace IRIX syssgi()'s + */ +#define XFS_IOC_FSGEOMETRY_V1 _IOR ('X', 100, struct xfs_fsop_geom_v1) +#define XFS_IOC_FSBULKSTAT _IOWR('X', 101, struct xfs_fsop_bulkreq) +#define XFS_IOC_FSBULKSTAT_SINGLE _IOWR('X', 102, struct xfs_fsop_bulkreq) +#define XFS_IOC_FSINUMBERS _IOWR('X', 103, struct xfs_fsop_bulkreq) +#define XFS_IOC_PATH_TO_FSHANDLE _IOWR('X', 104, struct xfs_fsop_handlereq) +#define XFS_IOC_PATH_TO_HANDLE _IOWR('X', 105, struct xfs_fsop_handlereq) +#define XFS_IOC_FD_TO_HANDLE _IOWR('X', 106, struct xfs_fsop_handlereq) +#define XFS_IOC_OPEN_BY_HANDLE _IOWR('X', 107, struct xfs_fsop_handlereq) +#define XFS_IOC_READLINK_BY_HANDLE _IOWR('X', 108, struct xfs_fsop_handlereq) +#define XFS_IOC_SWAPEXT _IOWR('X', 109, struct xfs_swapext) +#define XFS_IOC_FSGROWFSDATA _IOW ('X', 110, struct xfs_growfs_data) +#define XFS_IOC_FSGROWFSLOG _IOW ('X', 111, struct xfs_growfs_log) +#define XFS_IOC_FSGROWFSRT _IOW ('X', 112, struct xfs_growfs_rt) +#define XFS_IOC_FSCOUNTS _IOR ('X', 113, struct xfs_fsop_counts) +#define XFS_IOC_SET_RESBLKS _IOWR('X', 114, struct xfs_fsop_resblks) +#define XFS_IOC_GET_RESBLKS _IOR ('X', 115, struct xfs_fsop_resblks) +#define XFS_IOC_ERROR_INJECTION _IOW ('X', 116, struct xfs_error_injection) +#define XFS_IOC_ERROR_CLEARALL _IOW ('X', 117, struct xfs_error_injection) +/* XFS_IOC_ATTRCTL_BY_HANDLE -- deprecated 118 */ +/* XFS_IOC_FREEZE -- FIFREEZE 119 */ +/* XFS_IOC_THAW -- FITHAW 120 */ +#define XFS_IOC_FSSETDM_BY_HANDLE _IOW ('X', 121, struct xfs_fsop_setdm_handlereq) +#define XFS_IOC_ATTRLIST_BY_HANDLE _IOW ('X', 122, struct xfs_fsop_attrlist_handlereq) +#define XFS_IOC_ATTRMULTI_BY_HANDLE _IOW ('X', 123, struct xfs_fsop_attrmulti_handlereq) +#define XFS_IOC_FSGEOMETRY _IOR ('X', 124, struct xfs_fsop_geom) +#define XFS_IOC_GOINGDOWN _IOR ('X', 125, __uint32_t) +/* XFS_IOC_GETFSUUID ---------- deprecated 140 */ + + +#ifndef HAVE_BBMACROS +/* + * Block I/O parameterization. A basic block (BB) is the lowest size of + * filesystem allocation, and must equal 512. Length units given to bio + * routines are in BB's. + */ +#define BBSHIFT 9 +#define BBSIZE (1<<BBSHIFT) +#define BBMASK (BBSIZE-1) +#define BTOBB(bytes) (((uint64_t)(bytes) + BBSIZE - 1) >> BBSHIFT) +#define BTOBBT(bytes) ((uint64_t)(bytes) >> BBSHIFT) +#define BBTOB(bbs) ((bbs) << BBSHIFT) +#endif + +#endif /* XFS_FS_H_ */ diff --git a/extlinux/xfs_sb.h b/extlinux/xfs_sb.h new file mode 100644 index 0000000..8f72d6a --- /dev/null +++ b/extlinux/xfs_sb.h @@ -0,0 +1,476 @@ +/* + * Taken from Linux kernel tree (linux/fs/xfs) + * + * Copyright (c) 2000-2005 Silicon Graphics, Inc. + * All Rights Reserved. + * + * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef XFS_SB_H_ +#define XFS_SB_H__ + +#include <stddef.h> + +#include <sys/types.h> +#include <uuid/uuid.h> + +/* + * Super block + * Fits into a sector-sized buffer at address 0 of each allocation group. + * Only the first of these is ever updated except during growfs. + */ + +struct xfs_buf; +struct xfs_mount; + +#define XFS_SB_MAGIC "XFSB" /* 'XFSB' */ +#define XFS_SB_VERSION_1 1 /* 5.3, 6.0.1, 6.1 */ +#define XFS_SB_VERSION_2 2 /* 6.2 - attributes */ +#define XFS_SB_VERSION_3 3 /* 6.2 - new inode version */ +#define XFS_SB_VERSION_4 4 /* 6.2+ - bitmask version */ +#define XFS_SB_VERSION_NUMBITS 0x000f +#define XFS_SB_VERSION_ALLFBITS 0xfff0 +#define XFS_SB_VERSION_SASHFBITS 0xf000 +#define XFS_SB_VERSION_REALFBITS 0x0ff0 +#define XFS_SB_VERSION_ATTRBIT 0x0010 +#define XFS_SB_VERSION_NLINKBIT 0x0020 +#define XFS_SB_VERSION_QUOTABIT 0x0040 +#define XFS_SB_VERSION_ALIGNBIT 0x0080 +#define XFS_SB_VERSION_DALIGNBIT 0x0100 +#define XFS_SB_VERSION_SHAREDBIT 0x0200 +#define XFS_SB_VERSION_LOGV2BIT 0x0400 +#define XFS_SB_VERSION_SECTORBIT 0x0800 +#define XFS_SB_VERSION_EXTFLGBIT 0x1000 +#define XFS_SB_VERSION_DIRV2BIT 0x2000 +#define XFS_SB_VERSION_BORGBIT 0x4000 /* ASCII only case-insens. */ +#define XFS_SB_VERSION_MOREBITSBIT 0x8000 +#define XFS_SB_VERSION_OKSASHFBITS \ + (XFS_SB_VERSION_EXTFLGBIT | \ + XFS_SB_VERSION_DIRV2BIT | \ + XFS_SB_VERSION_BORGBIT) +#define XFS_SB_VERSION_OKREALFBITS \ + (XFS_SB_VERSION_ATTRBIT | \ + XFS_SB_VERSION_NLINKBIT | \ + XFS_SB_VERSION_QUOTABIT | \ + XFS_SB_VERSION_ALIGNBIT | \ + XFS_SB_VERSION_DALIGNBIT | \ + XFS_SB_VERSION_SHAREDBIT | \ + XFS_SB_VERSION_LOGV2BIT | \ + XFS_SB_VERSION_SECTORBIT | \ + XFS_SB_VERSION_MOREBITSBIT) +#define XFS_SB_VERSION_OKREALBITS \ + (XFS_SB_VERSION_NUMBITS | \ + XFS_SB_VERSION_OKREALFBITS | \ + XFS_SB_VERSION_OKSASHFBITS) + +/* + * There are two words to hold XFS "feature" bits: the original + * word, sb_versionnum, and sb_features2. Whenever a bit is set in + * sb_features2, the feature bit XFS_SB_VERSION_MOREBITSBIT must be set. + * + * These defines represent bits in sb_features2. + */ +#define XFS_SB_VERSION2_REALFBITS 0x00ffffff /* Mask: features */ +#define XFS_SB_VERSION2_RESERVED1BIT 0x00000001 +#define XFS_SB_VERSION2_LAZYSBCOUNTBIT 0x00000002 /* Superblk counters */ +#define XFS_SB_VERSION2_RESERVED4BIT 0x00000004 +#define XFS_SB_VERSION2_ATTR2BIT 0x00000008 /* Inline attr rework */ +#define XFS_SB_VERSION2_PARENTBIT 0x00000010 /* parent pointers */ +#define XFS_SB_VERSION2_PROJID32BIT 0x00000080 /* 32 bit project id */ + +#define XFS_SB_VERSION2_OKREALFBITS \ + (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \ + XFS_SB_VERSION2_ATTR2BIT | \ + XFS_SB_VERSION2_PROJID32BIT) +#define XFS_SB_VERSION2_OKSASHFBITS \ + (0) +#define XFS_SB_VERSION2_OKREALBITS \ + (XFS_SB_VERSION2_OKREALFBITS | \ + XFS_SB_VERSION2_OKSASHFBITS ) + +/* + * Superblock - in core version. Must match the ondisk version below. + * Must be padded to 64 bit alignment. + */ +typedef struct xfs_sb { + uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */ + uint32_t sb_blocksize; /* logical block size, bytes */ + xfs_drfsbno_t sb_dblocks; /* number of data blocks */ + xfs_drfsbno_t sb_rblocks; /* number of realtime blocks */ + xfs_drtbno_t sb_rextents; /* number of realtime extents */ + uuid_t sb_uuid; /* file system unique id */ + xfs_dfsbno_t sb_logstart; /* starting block of log if internal */ + xfs_ino_t sb_rootino; /* root inode number */ + xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */ + xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */ + xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */ + xfs_agblock_t sb_agblocks; /* size of an allocation group */ + xfs_agnumber_t sb_agcount; /* number of allocation groups */ + xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */ + xfs_extlen_t sb_logblocks; /* number of log blocks */ + uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */ + uint16_t sb_sectsize; /* volume sector size, bytes */ + uint16_t sb_inodesize; /* inode size, bytes */ + uint16_t sb_inopblock; /* inodes per block */ + char sb_fname[12]; /* file system name */ + uint8_t sb_blocklog; /* log2 of sb_blocksize */ + uint8_t sb_sectlog; /* log2 of sb_sectsize */ + uint8_t sb_inodelog; /* log2 of sb_inodesize */ + uint8_t sb_inopblog; /* log2 of sb_inopblock */ + uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */ + uint8_t sb_rextslog; /* log2 of sb_rextents */ + uint8_t sb_inprogress; /* mkfs is in progress, don't mount */ + uint8_t sb_imax_pct; /* max % of fs for inode space */ + /* statistics */ + /* + * These fields must remain contiguous. If you really + * want to change their layout, make sure you fix the + * code in xfs_trans_apply_sb_deltas(). + */ + uint64_t sb_icount; /* allocated inodes */ + uint64_t sb_ifree; /* free inodes */ + uint64_t sb_fdblocks; /* free data blocks */ + uint64_t sb_frextents; /* free realtime extents */ + /* + * End contiguous fields. + */ + xfs_ino_t sb_uquotino; /* user quota inode */ + xfs_ino_t sb_gquotino; /* group quota inode */ + uint16_t sb_qflags; /* quota flags */ + uint8_t sb_flags; /* misc. flags */ + uint8_t sb_shared_vn; /* shared version number */ + xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */ + uint32_t sb_unit; /* stripe or raid unit */ + uint32_t sb_width; /* stripe or raid width */ + uint8_t sb_dirblklog; /* log2 of dir block size (fsbs) */ + uint8_t sb_logsectlog; /* log2 of the log sector size */ + uint16_t sb_logsectsize; /* sector size for the log, bytes */ + uint32_t sb_logsunit; /* stripe unit size for the log */ + uint32_t sb_features2; /* additional feature bits */ + + /* + * bad features2 field as a result of failing to pad the sb + * structure to 64 bits. Some machines will be using this field + * for features2 bits. Easiest just to mark it bad and not use + * it for anything else. + */ + uint32_t sb_bad_features2; + + /* must be padded to 64 bit alignment */ +} xfs_sb_t; + +/* + * Sequence number values for the fields. + */ +typedef enum { + XFS_SBS_MAGICNUM, XFS_SBS_BLOCKSIZE, XFS_SBS_DBLOCKS, XFS_SBS_RBLOCKS, + XFS_SBS_REXTENTS, XFS_SBS_UUID, XFS_SBS_LOGSTART, XFS_SBS_ROOTINO, + XFS_SBS_RBMINO, XFS_SBS_RSUMINO, XFS_SBS_REXTSIZE, XFS_SBS_AGBLOCKS, + XFS_SBS_AGCOUNT, XFS_SBS_RBMBLOCKS, XFS_SBS_LOGBLOCKS, + XFS_SBS_VERSIONNUM, XFS_SBS_SECTSIZE, XFS_SBS_INODESIZE, + XFS_SBS_INOPBLOCK, XFS_SBS_FNAME, XFS_SBS_BLOCKLOG, + XFS_SBS_SECTLOG, XFS_SBS_INODELOG, XFS_SBS_INOPBLOG, XFS_SBS_AGBLKLOG, + XFS_SBS_REXTSLOG, XFS_SBS_INPROGRESS, XFS_SBS_IMAX_PCT, XFS_SBS_ICOUNT, + XFS_SBS_IFREE, XFS_SBS_FDBLOCKS, XFS_SBS_FREXTENTS, XFS_SBS_UQUOTINO, + XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN, + XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG, + XFS_SBS_LOGSECTLOG, XFS_SBS_LOGSECTSIZE, XFS_SBS_LOGSUNIT, + XFS_SBS_FEATURES2, XFS_SBS_BAD_FEATURES2, + XFS_SBS_FIELDCOUNT +} xfs_sb_field_t; + +/* + * Mask values, defined based on the xfs_sb_field_t values. + * Only define the ones we're using. + */ +#define XFS_SB_MVAL(x) (1LL << XFS_SBS_ ## x) +#define XFS_SB_UUID XFS_SB_MVAL(UUID) +#define XFS_SB_FNAME XFS_SB_MVAL(FNAME) +#define XFS_SB_ROOTINO XFS_SB_MVAL(ROOTINO) +#define XFS_SB_RBMINO XFS_SB_MVAL(RBMINO) +#define XFS_SB_RSUMINO XFS_SB_MVAL(RSUMINO) +#define XFS_SB_VERSIONNUM XFS_SB_MVAL(VERSIONNUM) +#define XFS_SB_UQUOTINO XFS_SB_MVAL(UQUOTINO) +#define XFS_SB_GQUOTINO XFS_SB_MVAL(GQUOTINO) +#define XFS_SB_QFLAGS XFS_SB_MVAL(QFLAGS) +#define XFS_SB_SHARED_VN XFS_SB_MVAL(SHARED_VN) +#define XFS_SB_UNIT XFS_SB_MVAL(UNIT) +#define XFS_SB_WIDTH XFS_SB_MVAL(WIDTH) +#define XFS_SB_ICOUNT XFS_SB_MVAL(ICOUNT) +#define XFS_SB_IFREE XFS_SB_MVAL(IFREE) +#define XFS_SB_FDBLOCKS XFS_SB_MVAL(FDBLOCKS) +#define XFS_SB_FEATURES2 XFS_SB_MVAL(FEATURES2) +#define XFS_SB_BAD_FEATURES2 XFS_SB_MVAL(BAD_FEATURES2) +#define XFS_SB_NUM_BITS ((int)XFS_SBS_FIELDCOUNT) +#define XFS_SB_ALL_BITS ((1LL << XFS_SB_NUM_BITS) - 1) +#define XFS_SB_MOD_BITS \ + (XFS_SB_UUID | XFS_SB_ROOTINO | XFS_SB_RBMINO | XFS_SB_RSUMINO | \ + XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \ + XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH | \ + XFS_SB_ICOUNT | XFS_SB_IFREE | XFS_SB_FDBLOCKS | XFS_SB_FEATURES2 | \ + XFS_SB_BAD_FEATURES2) + + +/* + * Misc. Flags - warning - these will be cleared by xfs_repair unless + * a feature bit is set when the flag is used. + */ +#define XFS_SBF_NOFLAGS 0x00 /* no flags set */ +#define XFS_SBF_READONLY 0x01 /* only read-only mounts allowed */ + +/* + * define max. shared version we can interoperate with + */ +#define XFS_SB_MAX_SHARED_VN 0 + +#define XFS_SB_VERSION_NUM(sbp) ((sbp)->sb_versionnum & XFS_SB_VERSION_NUMBITS) + +static inline int xfs_sb_good_version(xfs_sb_t *sbp) +{ + /* We always support version 1-3 */ + if (sbp->sb_versionnum >= XFS_SB_VERSION_1 && + sbp->sb_versionnum <= XFS_SB_VERSION_3) + return 1; + + /* We support version 4 if all feature bits are supported */ + if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) { + if ((sbp->sb_versionnum & ~XFS_SB_VERSION_OKREALBITS) || + ((sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) && + (sbp->sb_features2 & ~XFS_SB_VERSION2_OKREALBITS))) + return 0; + + if ((sbp->sb_versionnum & XFS_SB_VERSION_SHAREDBIT) && + sbp->sb_shared_vn > XFS_SB_MAX_SHARED_VN) + return 0; + + return 1; + } + + return 0; +} + +/* + * Detect a mismatched features2 field. Older kernels read/wrote + * this into the wrong slot, so to be safe we keep them in sync. + */ +static inline int xfs_sb_has_mismatched_features2(xfs_sb_t *sbp) +{ + return (sbp->sb_bad_features2 != sbp->sb_features2); +} + +static inline unsigned xfs_sb_version_tonew(unsigned v) +{ + if (v == XFS_SB_VERSION_1) + return XFS_SB_VERSION_4; + + if (v == XFS_SB_VERSION_2) + return XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT; + + return XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT | + XFS_SB_VERSION_NLINKBIT; +} + +static inline unsigned xfs_sb_version_toold(unsigned v) +{ + if (v & (XFS_SB_VERSION_QUOTABIT | XFS_SB_VERSION_ALIGNBIT)) + return 0; + if (v & XFS_SB_VERSION_NLINKBIT) + return XFS_SB_VERSION_3; + if (v & XFS_SB_VERSION_ATTRBIT) + return XFS_SB_VERSION_2; + return XFS_SB_VERSION_1; +} + +static inline int xfs_sb_version_hasattr(xfs_sb_t *sbp) +{ + return sbp->sb_versionnum == XFS_SB_VERSION_2 || + sbp->sb_versionnum == XFS_SB_VERSION_3 || + (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 && + (sbp->sb_versionnum & XFS_SB_VERSION_ATTRBIT)); +} + +static inline void xfs_sb_version_addattr(xfs_sb_t *sbp) +{ + if (sbp->sb_versionnum == XFS_SB_VERSION_1) + sbp->sb_versionnum = XFS_SB_VERSION_2; + else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) + sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT; + else + sbp->sb_versionnum = XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT; +} + +static inline int xfs_sb_version_hasnlink(xfs_sb_t *sbp) +{ + return sbp->sb_versionnum == XFS_SB_VERSION_3 || + (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 && + (sbp->sb_versionnum & XFS_SB_VERSION_NLINKBIT)); +} + +static inline void xfs_sb_version_addnlink(xfs_sb_t *sbp) +{ + if (sbp->sb_versionnum <= XFS_SB_VERSION_2) + sbp->sb_versionnum = XFS_SB_VERSION_3; + else + sbp->sb_versionnum |= XFS_SB_VERSION_NLINKBIT; +} + +static inline int xfs_sb_version_hasquota(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 && + (sbp->sb_versionnum & XFS_SB_VERSION_QUOTABIT); +} + +static inline void xfs_sb_version_addquota(xfs_sb_t *sbp) +{ + if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) + sbp->sb_versionnum |= XFS_SB_VERSION_QUOTABIT; + else + sbp->sb_versionnum = xfs_sb_version_tonew(sbp->sb_versionnum) | + XFS_SB_VERSION_QUOTABIT; +} + +static inline int xfs_sb_version_hasalign(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 && + (sbp->sb_versionnum & XFS_SB_VERSION_ALIGNBIT); +} + +static inline int xfs_sb_version_hasdalign(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 && + (sbp->sb_versionnum & XFS_SB_VERSION_DALIGNBIT); +} + +static inline int xfs_sb_version_hasshared(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 && + (sbp->sb_versionnum & XFS_SB_VERSION_SHAREDBIT); +} + +static inline int xfs_sb_version_hasdirv2(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 && + (sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT); +} + +static inline int xfs_sb_version_haslogv2(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 && + (sbp->sb_versionnum & XFS_SB_VERSION_LOGV2BIT); +} + +static inline int xfs_sb_version_hasextflgbit(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 && + (sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT); +} + +static inline int xfs_sb_version_hassector(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 && + (sbp->sb_versionnum & XFS_SB_VERSION_SECTORBIT); +} + +static inline int xfs_sb_version_hasasciici(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 && + (sbp->sb_versionnum & XFS_SB_VERSION_BORGBIT); +} + +static inline int xfs_sb_version_hasmorebits(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 && + (sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT); +} + +/* + * sb_features2 bit version macros. + * + * For example, for a bit defined as XFS_SB_VERSION2_FUNBIT, has a macro: + * + * SB_VERSION_HASFUNBIT(xfs_sb_t *sbp) + * ((xfs_sb_version_hasmorebits(sbp) && + * ((sbp)->sb_features2 & XFS_SB_VERSION2_FUNBIT) + */ + +static inline int xfs_sb_version_haslazysbcount(xfs_sb_t *sbp) +{ + return xfs_sb_version_hasmorebits(sbp) && + (sbp->sb_features2 & XFS_SB_VERSION2_LAZYSBCOUNTBIT); +} + +static inline int xfs_sb_version_hasattr2(xfs_sb_t *sbp) +{ + return xfs_sb_version_hasmorebits(sbp) && + (sbp->sb_features2 & XFS_SB_VERSION2_ATTR2BIT); +} + +static inline void xfs_sb_version_addattr2(xfs_sb_t *sbp) +{ + sbp->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT; + sbp->sb_features2 |= XFS_SB_VERSION2_ATTR2BIT; +} + +static inline void xfs_sb_version_removeattr2(xfs_sb_t *sbp) +{ + sbp->sb_features2 &= ~XFS_SB_VERSION2_ATTR2BIT; + if (!sbp->sb_features2) + sbp->sb_versionnum &= ~XFS_SB_VERSION_MOREBITSBIT; +} + +static inline int xfs_sb_version_hasprojid32bit(xfs_sb_t *sbp) +{ + return xfs_sb_version_hasmorebits(sbp) && + (sbp->sb_features2 & XFS_SB_VERSION2_PROJID32BIT); +} + +/* + * end of superblock version macros + */ + +#define XFS_SB_DADDR ((xfs_daddr_t)0) /* daddr in filesystem/ag */ +#define XFS_SB_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_SB_DADDR) +#define XFS_BUF_TO_SBP(bp) ((xfs_dsb_t *)((bp)->b_addr)) + +#define XFS_HDR_BLOCK(mp,d) ((xfs_agblock_t)XFS_BB_TO_FSBT(mp,d)) +#define XFS_DADDR_TO_FSB(mp,d) XFS_AGB_TO_FSB(mp, \ + xfs_daddr_to_agno(mp,d), xfs_daddr_to_agbno(mp,d)) +#define XFS_FSB_TO_DADDR(mp,fsbno) XFS_AGB_TO_DADDR(mp, \ + XFS_FSB_TO_AGNO(mp,fsbno), XFS_FSB_TO_AGBNO(mp,fsbno)) + +/* + * File system sector to basic block conversions. + */ +#define XFS_FSS_TO_BB(mp,sec) ((sec) << (mp)->m_sectbb_log) + +/* + * File system block to basic block conversions. + */ +#define XFS_FSB_TO_BB(mp,fsbno) ((fsbno) << (mp)->m_blkbb_log) +#define XFS_BB_TO_FSB(mp,bb) \ + (((bb) + (XFS_FSB_TO_BB(mp,1) - 1)) >> (mp)->m_blkbb_log) +#define XFS_BB_TO_FSBT(mp,bb) ((bb) >> (mp)->m_blkbb_log) + +/* + * File system block to byte conversions. + */ +#define XFS_FSB_TO_B(mp,fsbno) ((xfs_fsize_t)(fsbno) << (mp)->m_sb.sb_blocklog) +#define XFS_B_TO_FSB(mp,b) \ + ((((uint64_t)(b)) + (mp)->m_blockmask) >> (mp)->m_sb.sb_blocklog) +#define XFS_B_TO_FSBT(mp,b) (((uint64_t)(b)) >> (mp)->m_sb.sb_blocklog) +#define XFS_B_FSB_OFFSET(mp,b) ((b) & (mp)->m_blockmask) + +#endif /* XFS_SB_H_ */ diff --git a/extlinux/xfs_types.h b/extlinux/xfs_types.h new file mode 100644 index 0000000..9280886 --- /dev/null +++ b/extlinux/xfs_types.h @@ -0,0 +1,135 @@ +/* + * Taken from Linux kernel tree (linux/fs/xfs) + * + * Copyright (c) 2000-2005 Silicon Graphics, Inc. + * All Rights Reserved. + * + * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef XFS_TYPES_H_ +#define XFS_TYPES_H_ + +#include <stddef.h> + +#include <sys/types.h> + +typedef enum { B_FALSE,B_TRUE } boolean_t; +typedef uint32_t prid_t; /* project ID */ +typedef uint32_t inst_t; /* an instruction */ + +typedef int64_t xfs_off_t; /* <file offset> type */ +typedef unsigned long long xfs_ino_t; /* <inode> type */ +typedef int64_t xfs_daddr_t; /* <disk address> type */ +typedef char * xfs_caddr_t; /* <core address> type */ +typedef uint32_t xfs_dev_t; +typedef uint32_t xfs_nlink_t; + +/* __psint_t is the same size as a pointer */ +typedef int32_t __psint_t; +typedef uint32_t __psunsigned_t; + +typedef uint32_t xfs_agblock_t; /* blockno in alloc. group */ +typedef uint32_t xfs_extlen_t; /* extent length in blocks */ +typedef uint32_t xfs_agnumber_t; /* allocation group number */ +typedef int32_t xfs_extnum_t; /* # of extents in a file */ +typedef int16_t xfs_aextnum_t; /* # extents in an attribute fork */ +typedef int64_t xfs_fsize_t; /* bytes in a file */ +typedef uint64_t xfs_ufsize_t; /* unsigned bytes in a file */ + +typedef int32_t xfs_suminfo_t; /* type of bitmap summary info */ +typedef int32_t xfs_rtword_t; /* word type for bitmap manipulations */ + +typedef int64_t xfs_lsn_t; /* log sequence number */ +typedef int32_t xfs_tid_t; /* transaction identifier */ + +typedef uint32_t xfs_dablk_t; /* dir/attr block number (in file) */ +typedef uint32_t xfs_dahash_t; /* dir/attr hash value */ + +/* + * These types are 64 bits on disk but are either 32 or 64 bits in memory. + * Disk based types: + */ +typedef uint64_t xfs_dfsbno_t; /* blockno in filesystem (agno|agbno) */ +typedef uint64_t xfs_drfsbno_t; /* blockno in filesystem (raw) */ +typedef uint64_t xfs_drtbno_t; /* extent (block) in realtime area */ +typedef uint64_t xfs_dfiloff_t; /* block number in a file */ +typedef uint64_t xfs_dfilblks_t; /* number of blocks in a file */ + +/* + * Memory based types are conditional. + */ +typedef uint64_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */ +typedef uint64_t xfs_rfsblock_t; /* blockno in filesystem (raw) */ +typedef uint64_t xfs_rtblock_t; /* extent (block) in realtime area */ +typedef int64_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */ + +typedef uint64_t xfs_fileoff_t; /* block number in a file */ +typedef int64_t xfs_sfiloff_t; /* signed block number in a file */ +typedef uint64_t xfs_filblks_t; /* number of blocks in a file */ + +/* + * Null values for the types. + */ +#define NULLDFSBNO ((xfs_dfsbno_t)-1) +#define NULLDRFSBNO ((xfs_drfsbno_t)-1) +#define NULLDRTBNO ((xfs_drtbno_t)-1) +#define NULLDFILOFF ((xfs_dfiloff_t)-1) + +#define NULLFSBLOCK ((xfs_fsblock_t)-1) +#define NULLRFSBLOCK ((xfs_rfsblock_t)-1) +#define NULLRTBLOCK ((xfs_rtblock_t)-1) +#define NULLFILEOFF ((xfs_fileoff_t)-1) + +#define NULLAGBLOCK ((xfs_agblock_t)-1) +#define NULLAGNUMBER ((xfs_agnumber_t)-1) +#define NULLEXTNUM ((xfs_extnum_t)-1) + +#define NULLCOMMITLSN ((xfs_lsn_t)-1) + +/* + * Max values for extlen, extnum, aextnum. + */ +#define MAXEXTLEN ((xfs_extlen_t)0x001fffff) /* 21 bits */ +#define MAXEXTNUM ((xfs_extnum_t)0x7fffffff) /* signed int */ +#define MAXAEXTNUM ((xfs_aextnum_t)0x7fff) /* signed short */ + +/* + * Min numbers of data/attr fork btree root pointers. + */ +#define MINDBTPTRS 3 +#define MINABTPTRS 2 + +/* + * MAXNAMELEN is the length (including the terminating null) of + * the longest permissible file (component) name. + */ +#define MAXNAMELEN 256 + +typedef enum { + XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi +} xfs_lookup_t; + +typedef enum { + XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi, + XFS_BTNUM_MAX +} xfs_btnum_t; + +struct xfs_name { + const unsigned char *name; + int len; +}; + +#endif /* XFS_TYPES_H_ */ |