#include <sys/mount.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/sysinfo.h>
#include <uuid/uuid.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/vfs.h>
#include <sys/statfs.h>
#include <linux/magic.h>
-#include <sys/utsname.h>
-#include <linux/version.h>
+#include <getopt.h>
+
+#include <btrfsutil.h>
#include "kerncompat.h"
#include "radix-tree.h"
#include "volumes.h"
#include "ioctl.h"
#include "commands.h"
+#include "mkfs/common.h"
#ifndef BLKDISCARD
#define BLKDISCARD _IO(0x12,119)
return unique;
}
-/*
- * Insert a root item for temporary tree root
- *
- * Only used in make_btrfs_v2().
- */
-#define VERSION_TO_STRING3(a,b,c) #a "." #b "." #c, KERNEL_VERSION(a,b,c)
-#define VERSION_TO_STRING2(a,b) #a "." #b, KERNEL_VERSION(a,b,0)
-
-/*
- * Feature stability status and versions: compat <= safe <= default
- */
-static const struct btrfs_fs_feature {
- const char *name;
- u64 flag;
- const char *sysfs_name;
- /*
- * Compatibility with kernel of given version. Filesystem can be
- * mounted.
- */
- const char *compat_str;
- u32 compat_ver;
- /*
- * Considered safe for use, but is not on by default, even if the
- * kernel supports the feature.
- */
- const char *safe_str;
- u32 safe_ver;
- /*
- * Considered safe for use and will be turned on by default if
- * supported by the running kernel.
- */
- const char *default_str;
- u32 default_ver;
- const char *desc;
-} mkfs_features[] = {
- { "mixed-bg", BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS,
- "mixed_groups",
- VERSION_TO_STRING3(2,6,37),
- VERSION_TO_STRING3(2,6,37),
- NULL, 0,
- "mixed data and metadata block groups" },
- { "extref", BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF,
- "extended_iref",
- VERSION_TO_STRING2(3,7),
- VERSION_TO_STRING2(3,12),
- VERSION_TO_STRING2(3,12),
- "increased hardlink limit per file to 65536" },
- { "raid56", BTRFS_FEATURE_INCOMPAT_RAID56,
- "raid56",
- VERSION_TO_STRING2(3,9),
- NULL, 0,
- NULL, 0,
- "raid56 extended format" },
- { "skinny-metadata", BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA,
- "skinny_metadata",
- VERSION_TO_STRING2(3,10),
- VERSION_TO_STRING2(3,18),
- VERSION_TO_STRING2(3,18),
- "reduced-size metadata extent refs" },
- { "no-holes", BTRFS_FEATURE_INCOMPAT_NO_HOLES,
- "no_holes",
- VERSION_TO_STRING2(3,14),
- VERSION_TO_STRING2(4,0),
- NULL, 0,
- "no explicit hole extents for files" },
- /* Keep this one last */
- { "list-all", BTRFS_FEATURE_LIST_ALL, NULL }
-};
-
-static int parse_one_fs_feature(const char *name, u64 *flags)
-{
- int i;
- int found = 0;
-
- for (i = 0; i < ARRAY_SIZE(mkfs_features); i++) {
- if (name[0] == '^' &&
- !strcmp(mkfs_features[i].name, name + 1)) {
- *flags &= ~ mkfs_features[i].flag;
- found = 1;
- } else if (!strcmp(mkfs_features[i].name, name)) {
- *flags |= mkfs_features[i].flag;
- found = 1;
- }
- }
-
- return !found;
-}
-
-void btrfs_parse_features_to_string(char *buf, u64 flags)
-{
- int i;
-
- buf[0] = 0;
-
- for (i = 0; i < ARRAY_SIZE(mkfs_features); i++) {
- if (flags & mkfs_features[i].flag) {
- if (*buf)
- strcat(buf, ", ");
- strcat(buf, mkfs_features[i].name);
- }
- }
-}
-
-void btrfs_process_fs_features(u64 flags)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(mkfs_features); i++) {
- if (flags & mkfs_features[i].flag) {
- printf("Turning ON incompat feature '%s': %s\n",
- mkfs_features[i].name,
- mkfs_features[i].desc);
- }
- }
-}
-
-void btrfs_list_all_fs_features(u64 mask_disallowed)
-{
- int i;
-
- fprintf(stderr, "Filesystem features available:\n");
- for (i = 0; i < ARRAY_SIZE(mkfs_features) - 1; i++) {
- const struct btrfs_fs_feature *feat = &mkfs_features[i];
-
- if (feat->flag & mask_disallowed)
- continue;
- fprintf(stderr, "%-20s- %s (0x%llx", feat->name, feat->desc,
- feat->flag);
- if (feat->compat_ver)
- fprintf(stderr, ", compat=%s", feat->compat_str);
- if (feat->safe_ver)
- fprintf(stderr, ", safe=%s", feat->safe_str);
- if (feat->default_ver)
- fprintf(stderr, ", default=%s", feat->default_str);
- fprintf(stderr, ")\n");
- }
-}
-
-/*
- * Return NULL if all features were parsed fine, otherwise return the name of
- * the first unparsed.
- */
-char* btrfs_parse_fs_features(char *namelist, u64 *flags)
-{
- char *this_char;
- char *save_ptr = NULL; /* Satisfy static checkers */
-
- for (this_char = strtok_r(namelist, ",", &save_ptr);
- this_char != NULL;
- this_char = strtok_r(NULL, ",", &save_ptr)) {
- if (parse_one_fs_feature(this_char, flags))
- return this_char;
- }
-
- return NULL;
-}
-
-void print_kernel_version(FILE *stream, u32 version)
-{
- u32 v[3];
-
- v[0] = version & 0xFF;
- v[1] = (version >> 8) & 0xFF;
- v[2] = version >> 16;
- fprintf(stream, "%u.%u", v[2], v[1]);
- if (v[0])
- fprintf(stream, ".%u", v[0]);
-}
-
-u32 get_running_kernel_version(void)
-{
- struct utsname utsbuf;
- char *tmp;
- char *saveptr = NULL;
- u32 version;
-
- uname(&utsbuf);
- if (strcmp(utsbuf.sysname, "Linux") != 0) {
- error("unsupported system: %s", utsbuf.sysname);
- exit(1);
- }
- /* 1.2.3-4-name */
- tmp = strchr(utsbuf.release, '-');
- if (tmp)
- *tmp = 0;
-
- tmp = strtok_r(utsbuf.release, ".", &saveptr);
- if (!string_is_numerical(tmp))
- return (u32)-1;
- version = atoi(tmp) << 16;
- tmp = strtok_r(NULL, ".", &saveptr);
- if (!string_is_numerical(tmp))
- return (u32)-1;
- version |= atoi(tmp) << 8;
- tmp = strtok_r(NULL, ".", &saveptr);
- if (tmp) {
- if (!string_is_numerical(tmp))
- return (u32)-1;
- version |= atoi(tmp);
- }
-
- return version;
-}
-
u64 btrfs_device_size(int fd, struct stat *st)
{
u64 size;
u32 sectorsize)
{
struct btrfs_super_block *disk_super;
- struct btrfs_super_block *super = root->fs_info->super_copy;
+ struct btrfs_fs_info *fs_info = root->fs_info;
+ struct btrfs_super_block *super = fs_info->super_copy;
struct btrfs_device *device;
struct btrfs_dev_item *dev_item;
char *buf = NULL;
device->total_bytes = device_total_bytes;
device->bytes_used = 0;
device->total_ios = 0;
- device->dev_root = root->fs_info->dev_root;
+ device->dev_root = fs_info->dev_root;
device->name = strdup(path);
if (!device->name) {
ret = -ENOMEM;
}
INIT_LIST_HEAD(&device->dev_list);
- ret = btrfs_add_device(trans, root, device);
+ ret = btrfs_add_device(trans, fs_info, device);
if (ret)
goto out;
BUG_ON(ret != sectorsize);
free(buf);
- list_add(&device->dev_list, &root->fs_info->fs_devices->devices);
- device->fs_devices = root->fs_info->fs_devices;
+ list_add(&device->dev_list, &fs_info->fs_devices->devices);
+ device->fs_devices = fs_info->fs_devices;
return 0;
out:
memset(buf, 0, len);
ret = pwrite(fd, buf, len, offset);
if (ret < 0) {
- error("cannot wipe existing superblock: %s", strerror(errno));
+ error("cannot wipe existing superblock: %m");
ret = -1;
} else if (ret != len) {
error("cannot wipe existing superblock: wrote %d of %zd", ret, len);
ret = fstat(fd, &st);
if (ret < 0) {
- error("unable to stat %s: %s", file, strerror(errno));
+ error("unable to stat %s: %m", file);
return 1;
}
btrfs_set_stack_inode_generation(&inode_item, trans->transid);
btrfs_set_stack_inode_size(&inode_item, 0);
btrfs_set_stack_inode_nlink(&inode_item, 1);
- btrfs_set_stack_inode_nbytes(&inode_item, root->nodesize);
+ btrfs_set_stack_inode_nbytes(&inode_item, root->fs_info->nodesize);
btrfs_set_stack_inode_mode(&inode_item, S_IFDIR | 0755);
btrfs_set_stack_timespec_sec(&inode_item.atime, now);
btrfs_set_stack_timespec_nsec(&inode_item.atime, 0);
return ret;
}
-static int is_reg_file(const char *path)
+int is_reg_file(const char *path)
{
struct stat statbuf;
return S_ISREG(statbuf.st_mode);
}
+int is_path_exist(const char *path)
+{
+ struct stat statbuf;
+ int ret;
+
+ ret = stat(path, &statbuf);
+ if (ret < 0) {
+ if (errno == ENOENT)
+ return 0;
+ else
+ return -errno;
+ }
+ return 1;
+}
+
/*
* This function checks if the given input parameter is
* an uuid or a path
fd = open(dev, O_RDONLY);
if (fd < 0) {
ret = -errno;
- error("cannot open %s: %s", dev, strerror(errno));
+ error("cannot open %s: %m", dev);
goto out;
}
return -1;
}
ret = open_file_or_dir(mp, dirstream);
- error_on(verbose && ret < 0, "can't access '%s': %s",
- path, strerror(errno));
+ error_on(verbose && ret < 0, "can't access '%s': %m",
+ path);
} else {
ret = btrfs_open_dir(path, dirstream, 1);
}
/*
* Do the following checks before calling open_file_or_dir():
* 1: path is in a btrfs filesystem
- * 2: path is a directory
+ * 2: path is a directory if dir_only is 1
*/
-int btrfs_open_dir(const char *path, DIR **dirstream, int verbose)
+int btrfs_open(const char *path, DIR **dirstream, int verbose, int dir_only)
{
struct statfs stfs;
struct stat st;
int ret;
if (statfs(path, &stfs) != 0) {
- error_on(verbose, "cannot access '%s': %s", path,
- strerror(errno));
+ error_on(verbose, "cannot access '%s': %m", path);
return -1;
}
}
if (stat(path, &st) != 0) {
- error_on(verbose, "cannot access '%s': %s", path,
- strerror(errno));
+ error_on(verbose, "cannot access '%s': %m", path);
return -1;
}
- if (!S_ISDIR(st.st_mode)) {
+ if (dir_only && !S_ISDIR(st.st_mode)) {
error_on(verbose, "not a directory: %s", path);
return -3;
}
ret = open_file_or_dir(path, dirstream);
if (ret < 0) {
- error_on(verbose, "cannot access '%s': %s", path,
- strerror(errno));
+ error_on(verbose, "cannot access '%s': %m", path);
}
return ret;
}
+int btrfs_open_dir(const char *path, DIR **dirstream, int verbose)
+{
+ return btrfs_open(path, dirstream, verbose, 1);
+}
+
+int btrfs_open_file_or_dir(const char *path, DIR **dirstream, int verbose)
+{
+ return btrfs_open(path, dirstream, verbose, 0);
+}
+
/* checks if a device is a loop device */
static int is_loop_device (const char* device) {
struct stat statbuf;
const char* file)
{
int ret;
- struct list_head *head;
- struct list_head *cur;
struct btrfs_device *device;
- head = &fs_devices->devices;
- list_for_each(cur, head) {
- device = list_entry(cur, struct btrfs_device, dev_list);
-
+ list_for_each_entry(device, &fs_devices->devices, dev_list) {
if((ret = is_same_loop_file(device->name, file)))
return ret;
}
fd = open(file, O_RDONLY);
if (fd < 0) {
- error("mount check: cannot open %s: %s", file,
- strerror(errno));
+ error("mount check: cannot open %s: %m", file);
return -errno;
}
fd = open("/dev/btrfs-control", O_RDWR);
if (fd < 0) {
warning(
- "failed to open /dev/btrfs-control, skipping device registration: %s",
- strerror(errno));
+ "failed to open /dev/btrfs-control, skipping device registration: %m");
return -errno;
}
memset(&args, 0, sizeof(args));
strncpy_null(args.name, fname);
ret = ioctl(fd, BTRFS_IOC_SCAN_DEV, &args);
if (ret < 0) {
- error("device scan failed on '%s': %s", fname,
- strerror(errno));
+ error("device scan failed on '%s': %m", fname);
ret = -errno;
}
close(fd);
return -1;
trans = btrfs_start_transaction(root, 1);
+ BUG_ON(IS_ERR(trans));
__strncpy_null(root->fs_info->super_copy->label, label, BTRFS_LABEL_SIZE - 1);
btrfs_commit_transaction(trans, root);
fd = open(mount_path, O_RDONLY | O_NOATIME);
if (fd < 0) {
- error("unable to access %s: %s", mount_path, strerror(errno));
+ error("unable to access %s: %m", mount_path);
return -1;
}
memset(label, 0, sizeof(label));
__strncpy_null(label, labelp, BTRFS_LABEL_SIZE - 1);
if (ioctl(fd, BTRFS_IOC_SET_FSLABEL, label) < 0) {
- error("unable to set label of %s: %s", mount_path,
- strerror(errno));
+ error("unable to set label of %s: %m", mount_path);
close(fd);
return -1;
}
fd = open(mount_path, O_RDONLY | O_NOATIME);
if (fd < 0) {
- error("unable to access %s: %s", mount_path, strerror(errno));
+ error("unable to access %s: %m", mount_path);
return -1;
}
ret = ioctl(fd, BTRFS_IOC_GET_FSLABEL, label);
if (ret < 0) {
if (errno != ENOTTY)
- error("unable to get label of %s: %s", mount_path,
- strerror(errno));
+ error("unable to get label of %s: %m", mount_path);
ret = -errno;
close(fd);
return ret;
char *s = strchr(p, '/');
const char *ptr_src_end = p + strlen(p);
char *ptr_parse_end = NULL;
+ enum btrfs_util_error err;
u64 level;
u64 id;
int fd;
path:
/* Path format like subv at 'my_subvol' is the fallback case */
- ret = test_issubvolume(p);
- if (ret < 0 || !ret)
+ err = btrfs_util_is_subvolume(p);
+ if (err)
goto err;
fd = open(p, O_RDONLY);
if (fd < 0)
void close_file_or_dir(int fd, DIR *dirstream)
{
- if (dirstream)
+ int old_errno;
+
+ old_errno = errno;
+ if (dirstream) {
closedir(dirstream);
- else if (fd >= 0)
+ } else if (fd >= 0) {
close(fd);
+ }
+
+ errno = old_errno;
}
int get_device_info(int fd, u64 devid,
fd = open(path, O_RDONLY);
if (fd < 0) {
ret = -errno;
- error("cannot open %s: %s", path, strerror(errno));
+ error("cannot open %s: %m", path);
goto out;
}
ret = check_mounted_where(fd, path, mp, sizeof(mp),
return ret;
}
-#define isoctal(c) (((c) & ~7) == '0')
-
-static inline void translate(char *f, char *t)
+int get_fsid(const char *path, u8 *fsid, int silent)
{
- while (*f != '\0') {
- if (*f == '\\' &&
- isoctal(f[1]) && isoctal(f[2]) && isoctal(f[3])) {
- *t++ = 64*(f[1] & 7) + 8*(f[2] & 7) + (f[3] & 7);
- f += 4;
- } else
- *t++ = *f++;
- }
- *t = '\0';
- return;
-}
-
-/*
- * Checks if the swap device.
- * Returns 1 if swap device, < 0 on error or 0 if not swap device.
- */
-static int is_swap_device(const char *file)
-{
- FILE *f;
- struct stat st_buf;
- dev_t dev;
- ino_t ino = 0;
- char tmp[PATH_MAX];
- char buf[PATH_MAX];
- char *cp;
- int ret = 0;
-
- if (stat(file, &st_buf) < 0)
- return -errno;
- if (S_ISBLK(st_buf.st_mode))
- dev = st_buf.st_rdev;
- else if (S_ISREG(st_buf.st_mode)) {
- dev = st_buf.st_dev;
- ino = st_buf.st_ino;
- } else
- return 0;
-
- if ((f = fopen("/proc/swaps", "r")) == NULL)
- return 0;
+ int ret;
+ int fd;
+ struct btrfs_ioctl_fs_info_args args;
- /* skip the first line */
- if (fgets(tmp, sizeof(tmp), f) == NULL)
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ ret = -errno;
+ if (!silent)
+ error("failed to open %s: %s", path,
+ strerror(-ret));
goto out;
+ }
- while (fgets(tmp, sizeof(tmp), f) != NULL) {
- if ((cp = strchr(tmp, ' ')) != NULL)
- *cp = '\0';
- if ((cp = strchr(tmp, '\t')) != NULL)
- *cp = '\0';
- translate(tmp, buf);
- if (stat(buf, &st_buf) != 0)
- continue;
- if (S_ISBLK(st_buf.st_mode)) {
- if (dev == st_buf.st_rdev) {
- ret = 1;
- break;
- }
- } else if (S_ISREG(st_buf.st_mode)) {
- if (dev == st_buf.st_dev && ino == st_buf.st_ino) {
- ret = 1;
- break;
- }
- }
+ ret = ioctl(fd, BTRFS_IOC_FS_INFO, &args);
+ if (ret < 0) {
+ ret = -errno;
+ goto out;
}
-out:
- fclose(f);
+ memcpy(fsid, args.fsid, BTRFS_FSID_SIZE);
+ ret = 0;
+out:
+ if (fd != -1)
+ close(fd);
return ret;
}
-/*
- * Check for existing filesystem or partition table on device.
- * Returns:
- * 1 for existing fs or partition
- * 0 for nothing found
- * -1 for internal error
- */
-static int check_overwrite(const char *device)
+int is_seen_fsid(u8 *fsid, struct seen_fsid *seen_fsid_hash[])
{
- const char *type;
- blkid_probe pr = NULL;
- int ret;
- blkid_loff_t size;
+ u8 hash = fsid[0];
+ int slot = hash % SEEN_FSID_HASH_SIZE;
+ struct seen_fsid *seen = seen_fsid_hash[slot];
- if (!device || !*device)
- return 0;
+ while (seen) {
+ if (memcmp(seen->fsid, fsid, BTRFS_FSID_SIZE) == 0)
+ return 1;
- ret = -1; /* will reset on success of all setup calls */
+ seen = seen->next;
+ }
- pr = blkid_new_probe_from_filename(device);
- if (!pr)
- goto out;
+ return 0;
+}
- size = blkid_probe_get_size(pr);
- if (size < 0)
- goto out;
+int add_seen_fsid(u8 *fsid, struct seen_fsid *seen_fsid_hash[],
+ int fd, DIR *dirstream)
+{
+ u8 hash = fsid[0];
+ int slot = hash % SEEN_FSID_HASH_SIZE;
+ struct seen_fsid *seen = seen_fsid_hash[slot];
+ struct seen_fsid *alloc;
- /* nothing to overwrite on a 0-length device */
- if (size == 0) {
- ret = 0;
- goto out;
- }
+ if (!seen)
+ goto insert;
- ret = blkid_probe_enable_partitions(pr, 1);
- if (ret < 0)
- goto out;
+ while (1) {
+ if (memcmp(seen->fsid, fsid, BTRFS_FSID_SIZE) == 0)
+ return -EEXIST;
- ret = blkid_do_fullprobe(pr);
- if (ret < 0)
- goto out;
+ if (!seen->next)
+ break;
- /*
- * Blkid returns 1 for nothing found and 0 when it finds a signature,
- * but we want the exact opposite, so reverse the return value here.
- *
- * In addition print some useful diagnostics about what actually is
- * on the device.
- */
- if (ret) {
- ret = 0;
- goto out;
+ seen = seen->next;
}
- if (!blkid_probe_lookup_value(pr, "TYPE", &type, NULL)) {
- fprintf(stderr,
- "%s appears to contain an existing "
- "filesystem (%s).\n", device, type);
- } else if (!blkid_probe_lookup_value(pr, "PTTYPE", &type, NULL)) {
- fprintf(stderr,
- "%s appears to contain a partition "
- "table (%s).\n", device, type);
- } else {
- fprintf(stderr,
- "%s appears to contain something weird "
- "according to blkid\n", device);
- }
- ret = 1;
+insert:
+ alloc = malloc(sizeof(*alloc));
+ if (!alloc)
+ return -ENOMEM;
-out:
- if (pr)
- blkid_free_probe(pr);
- if (ret == -1)
- fprintf(stderr,
- "probe of %s failed, cannot detect "
- "existing filesystem.\n", device);
- return ret;
+ alloc->next = NULL;
+ memcpy(alloc->fsid, fsid, BTRFS_FSID_SIZE);
+ alloc->fd = fd;
+ alloc->dirstream = dirstream;
+
+ if (seen)
+ seen->next = alloc;
+ else
+ seen_fsid_hash[slot] = alloc;
+
+ return 0;
+}
+
+void free_seen_fsid(struct seen_fsid *seen_fsid_hash[])
+{
+ int slot;
+ struct seen_fsid *seen;
+ struct seen_fsid *next;
+
+ for (slot = 0; slot < SEEN_FSID_HASH_SIZE; slot++) {
+ seen = seen_fsid_hash[slot];
+ while (seen) {
+ next = seen->next;
+ close_file_or_dir(seen->fd, seen->dirstream);
+ free(seen);
+ seen = next;
+ }
+ seen_fsid_hash[slot] = NULL;
+ }
}
static int group_profile_devs_min(u64 flag)
}
}
-/*
- * Check if a device is suitable for btrfs
- * returns:
- * 1: something is wrong, an error is printed
- * 0: all is fine
- */
-int test_dev_for_mkfs(const char *file, int force_overwrite)
-{
- int ret, fd;
- struct stat st;
-
- ret = is_swap_device(file);
- if (ret < 0) {
- error("checking status of %s: %s", file, strerror(-ret));
- return 1;
- }
- if (ret == 1) {
- error("%s is a swap device", file);
- return 1;
- }
- if (!force_overwrite) {
- if (check_overwrite(file)) {
- error("use the -f option to force overwrite of %s",
- file);
- return 1;
- }
- }
- ret = check_mounted(file);
- if (ret < 0) {
- error("cannot check mount status of %s: %s", file,
- strerror(-ret));
- return 1;
- }
- if (ret == 1) {
- error("%s is mounted", file);
- return 1;
- }
- /* check if the device is busy */
- fd = open(file, O_RDWR|O_EXCL);
- if (fd < 0) {
- error("unable to open %s: %s", file, strerror(errno));
- return 1;
- }
- if (fstat(fd, &st)) {
- error("unable to stat %s: %s", file, strerror(errno));
- close(fd);
- return 1;
- }
- if (!S_ISBLK(st.st_mode)) {
- error("%s is not a block device", file);
- close(fd);
- return 1;
- }
- close(fd);
- return 0;
-}
-
int btrfs_scan_devices(void)
{
int fd = -1;
fd = open(path, O_RDONLY);
if (fd < 0) {
- error("cannot open %s: %s", path, strerror(errno));
+ error("cannot open %s: %m", path);
continue;
}
ret = btrfs_scan_one_device(fd, path, &tmp_devices,
return 0;
}
-int is_vol_small(const char *file)
-{
- int fd = -1;
- int e;
- struct stat st;
- u64 size;
-
- fd = open(file, O_RDONLY);
- if (fd < 0)
- return -errno;
- if (fstat(fd, &st) < 0) {
- e = -errno;
- close(fd);
- return e;
- }
- size = btrfs_device_size(fd, &st);
- if (size == 0) {
- close(fd);
- return -1;
- }
- if (size < BTRFS_MKFS_SMALL_VOLUME_SIZE) {
- close(fd);
- return 1;
- } else {
- close(fd);
- return 0;
- }
-}
-
/*
* This reads a line from the stdin and only returns non-zero if the
* first whitespace delimited token is a case insensitive match with yes
return ret;
}
-int test_minimum_size(const char *file, u32 nodesize)
-{
- int fd;
- struct stat statbuf;
-
- fd = open(file, O_RDONLY);
- if (fd < 0)
- return -errno;
- if (stat(file, &statbuf) < 0) {
- close(fd);
- return -errno;
- }
- if (btrfs_device_size(fd, &statbuf) < btrfs_min_dev_size(nodesize)) {
- close(fd);
- return 1;
- }
- close(fd);
- return 0;
-}
-
-
/*
* Test if path is a directory
* Returns:
return unit_mode;
}
+u64 div_factor(u64 num, int factor)
+{
+ if (factor == 10)
+ return num;
+ num *= factor;
+ num /= 10;
+ return num;
+}
+/*
+ * Get the length of the string converted from a u64 number.
+ *
+ * Result is equal to log10(num) + 1, but without the use of math library.
+ */
+int count_digits(u64 num)
+{
+ int ret = 0;
+
+ if (num == 0)
+ return 1;
+ while (num > 0) {
+ ret++;
+ num /= 10;
+ }
+ return ret;
+}
+
int string_is_numerical(const char *str)
{
if (!str)
return 1;
}
+int prefixcmp(const char *str, const char *prefix)
+{
+ for (; ; str++, prefix++)
+ if (!*prefix)
+ return 0;
+ else if (*str != *prefix)
+ return (unsigned char)*prefix - (unsigned char)*str;
+}
+
/* Subvolume helper functions */
/*
* test if name is a correct subvolume name
strcmp(name, ".") && strcmp(name, "..");
}
-/*
- * Test if path is a subvolume
- * Returns:
- * 0 - path exists but it is not a subvolume
- * 1 - path exists and it is a subvolume
- * < 0 - error
- */
-int test_issubvolume(const char *path)
-{
- struct stat st;
- struct statfs stfs;
- int res;
-
- res = stat(path, &st);
- if (res < 0)
- return -errno;
-
- if (st.st_ino != BTRFS_FIRST_FREE_OBJECTID || !S_ISDIR(st.st_mode))
- return 0;
-
- res = statfs(path, &stfs);
- if (res < 0)
- return -errno;
-
- return (int)stfs.f_type == BTRFS_SUPER_MAGIC;
-}
-
const char *subvol_strip_mountpoint(const char *mnt, const char *full_path)
{
int len = strlen(mnt);
if (!len)
return full_path;
+ if ((strncmp(mnt, full_path, len) != 0) || (full_path[len] != '/')) {
+ error("not on mount point: %s", mnt);
+ exit(1);
+ }
+
if (mnt[len - 1] != '/')
len += 1;
return full_path + len;
}
-/*
- * Returns
- * <0: Std error
- * 0: All fine
- * 1: Error; and error info printed to the terminal. Fixme.
- * 2: If the fullpath is root tree instead of subvol tree
- */
-int get_subvol_info(const char *fullpath, struct root_info *get_ri)
-{
- u64 sv_id;
- int ret = 1;
- int fd = -1;
- int mntfd = -1;
- char *mnt = NULL;
- const char *svpath = NULL;
- DIR *dirstream1 = NULL;
- DIR *dirstream2 = NULL;
-
- ret = test_issubvolume(fullpath);
- if (ret < 0)
- return ret;
- if (!ret) {
- error("not a subvolume: %s", fullpath);
- return 1;
- }
-
- ret = find_mount_root(fullpath, &mnt);
- if (ret < 0)
- return ret;
- if (ret > 0) {
- error("%s doesn't belong to btrfs mount point", fullpath);
- return 1;
- }
- ret = 1;
- svpath = subvol_strip_mountpoint(mnt, fullpath);
-
- fd = btrfs_open_dir(fullpath, &dirstream1, 1);
- if (fd < 0)
- goto out;
-
- ret = btrfs_list_get_path_rootid(fd, &sv_id);
- if (ret)
- goto out;
-
- mntfd = btrfs_open_dir(mnt, &dirstream2, 1);
- if (mntfd < 0)
- goto out;
-
- memset(get_ri, 0, sizeof(*get_ri));
- get_ri->root_id = sv_id;
-
- if (sv_id == BTRFS_FS_TREE_OBJECTID)
- ret = btrfs_get_toplevel_subvol(mntfd, get_ri);
- else
- ret = btrfs_get_subvol(mntfd, get_ri);
- if (ret)
- error("can't find '%s': %d", svpath, ret);
-
-out:
- close_file_or_dir(mntfd, dirstream2);
- close_file_or_dir(fd, dirstream1);
- free(mnt);
-
- return ret;
-}
-
+/* Set the seed manually */
void init_rand_seed(u64 seed)
{
int i;
return (u32)jrand48(rand_seed);
}
+/* Return random number in range [0, upper) */
unsigned int rand_range(unsigned int upper)
{
__init_seed();
return (unsigned int)(jrand48(rand_seed) % upper);
}
+int rand_int(void)
+{
+ return (int)(rand_u32());
+}
+
+u64 rand_u64(void)
+{
+ u64 ret = 0;
+
+ ret += rand_u32();
+ ret <<= 32;
+ ret += rand_u32();
+ return ret;
+}
+
+u16 rand_u16(void)
+{
+ return (u16)(rand_u32());
+}
+
+u8 rand_u8(void)
+{
+ return (u8)(rand_u32());
+}
+
void btrfs_config_init(void)
{
}
+
+/* Returns total size of main memory in bytes, -1UL if error. */
+unsigned long total_memory(void)
+{
+ struct sysinfo si;
+
+ if (sysinfo(&si) < 0) {
+ error("can't determine memory size");
+ return -1UL;
+ }
+ return si.totalram * si.mem_unit; /* bytes */
+}
+
+void print_device_info(struct btrfs_device *device, char *prefix)
+{
+ if (prefix)
+ printf("%s", prefix);
+ printf("Device: id = %llu, name = %s\n",
+ device->devid, device->name);
+}
+
+void print_all_devices(struct list_head *devices)
+{
+ struct btrfs_device *dev;
+
+ printf("All Devices:\n");
+ list_for_each_entry(dev, devices, dev_list)
+ print_device_info(dev, "\t");
+ printf("\n");
+}