X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=bcache.c;h=3cb5dfe99db03eef41954f9a556a54bcfe5f7602;hb=e460b80cb1f96eaa5b4b49bf7459ef73b415bfb7;hp=fe214833672cb356e38d7a165c0f10149f047ea8;hpb=2ef1c983d56438d4f53b1534545e6d0f54063ab8;p=bcachefs-tools-debian diff --git a/bcache.c b/bcache.c index fe21483..3cb5dfe 100644 --- a/bcache.c +++ b/bcache.c @@ -22,10 +22,6 @@ #include "bcache.h" -#define __KERNEL__ -#include -#undef __KERNEL__ - const char * const cache_state[] = { "active", "ro", @@ -48,6 +44,21 @@ const char * const csum_types[] = { NULL }; +const char * const compression_types[] = { + "none", + "lzo1x", + "gzip", + "xz", + NULL +}; + +const char * const error_actions[] = { + "continue", + "readonly", + "panic", + NULL +}; + const char * const bdev_cache_mode[] = { "writethrough", "writeback", @@ -150,11 +161,8 @@ ssize_t read_string_list_or_die(const char *opt, const char * const list[], const char *msg) { ssize_t v = read_string_list(opt, list); - if (v < 0) { - fprintf(stderr, "Bad %s %s\n", msg, opt); - exit(EXIT_FAILURE); - - } + if (v < 0) + die("Bad %s %s", msg, opt); return v; } @@ -391,8 +399,7 @@ static uint64_t bch_checksum_update(unsigned type, uint64_t crc, const void *dat case BCH_CSUM_CRC64: return bch_crc64_update(crc, data, len); default: - fprintf(stderr, "Unknown checksum type %u\n", type); - exit(EXIT_FAILURE); + die("Unknown checksum type %u", type); } } @@ -447,258 +454,51 @@ unsigned hatoi_validate(const char *s, const char *msg) { uint64_t v = hatoi(s); - if (v & (v - 1)) { - fprintf(stderr, "%s must be a power of two\n", msg); - exit(EXIT_FAILURE); - } + if (v & (v - 1)) + die("%s must be a power of two", msg); v /= 512; - if (v > USHRT_MAX) { - fprintf(stderr, "%s too large\n", msg); - exit(EXIT_FAILURE); - } + if (v > USHRT_MAX) + die("%s too large\n", msg); - if (!v) { - fprintf(stderr, "%s too small\n", msg); - exit(EXIT_FAILURE); - } + if (!v) + die("%s too small\n", msg); return v; } -static void do_write_sb(int fd, struct cache_sb *sb) -{ - char zeroes[SB_START] = {0}; - size_t bytes = ((void *) __bset_bkey_last(sb)) - (void *) sb; - - /* Zero start of disk */ - if (pwrite(fd, zeroes, SB_START, 0) != SB_START) { - perror("write error trying to zero start of disk\n"); - exit(EXIT_FAILURE); - } - /* Write superblock */ - if (pwrite(fd, sb, bytes, SB_START) != bytes) { - perror("write error trying to write superblock\n"); - exit(EXIT_FAILURE); - } - - fsync(fd); - close(fd); -} - -void write_backingdev_sb(int fd, unsigned block_size, unsigned *bucket_sizes, - unsigned mode, uint64_t data_offset, const char *label, - uuid_le user_uuid, uuid_le set_uuid) -{ - char uuid_str[40], set_uuid_str[40]; - struct cache_sb sb; - - memset(&sb, 0, sizeof(struct cache_sb)); - - sb.offset = SB_SECTOR; - sb.version = BCACHE_SB_VERSION_BDEV; - sb.magic = BCACHE_MAGIC; - uuid_generate(sb.disk_uuid.b); - sb.user_uuid = user_uuid; - sb.set_uuid = set_uuid; - sb.block_size = block_size; - - uuid_unparse(sb.disk_uuid.b, uuid_str); - uuid_unparse(sb.user_uuid.b, set_uuid_str); - if (label) - memcpy(sb.label, label, SB_LABEL_SIZE); - - SET_BDEV_CACHE_MODE(&sb, mode); - - if (data_offset != BDEV_DATA_START_DEFAULT) { - sb.version = BCACHE_SB_VERSION_BDEV_WITH_OFFSET; - sb.bdev_data_offset = data_offset; - } - - sb.csum = csum_set(&sb, BCH_CSUM_CRC64); - - printf("UUID: %s\n" - "Set UUID: %s\n" - "version: %u\n" - "block_size: %u\n" - "data_offset: %ju\n", - uuid_str, set_uuid_str, - (unsigned) sb.version, - sb.block_size, - data_offset); - - do_write_sb(fd, &sb); -} - -int dev_open(const char *dev, bool wipe_bcache) +int dev_open(const char *dev) { - struct cache_sb sb; blkid_probe pr; int fd; - char err[MAX_PATH]; - if ((fd = open(dev, O_RDWR|O_EXCL)) == -1) { - sprintf(err, "Can't open dev %s: %s\n", dev, strerror(errno)); - goto err; - } + if ((fd = open(dev, O_RDWR|O_EXCL)) == -1) + die("Can't open dev %s: %s\n", dev, strerror(errno)); - if (pread(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) { - sprintf(err, "Failed to read superblock"); - goto err; - } + if (!(pr = blkid_new_probe())) + die("Failed to create a new probe"); + if (blkid_probe_set_device(pr, fd, 0, 0)) + die("failed to set probe to device"); - if (!memcmp(&sb.magic, &BCACHE_MAGIC, 16) && !wipe_bcache) { - sprintf(err, "Already a bcache device on %s, " - "overwrite with --wipe-bcache\n", dev); - goto err; - } - - if (!(pr = blkid_new_probe())) { - sprintf(err, "Failed to create a new probe"); - goto err; - } - if (blkid_probe_set_device(pr, fd, 0, 0)) { - sprintf(err, "failed to set probe to device"); - goto err; - } /* enable ptable probing; superblock probing is enabled by default */ - if (blkid_probe_enable_partitions(pr, true)) { - sprintf(err, "Failed to enable partitions on probe"); - goto err; - } - if (!blkid_do_probe(pr)) { + if (blkid_probe_enable_partitions(pr, true)) + die("Failed to enable partitions on probe"); + + if (!blkid_do_probe(pr)) /* XXX wipefs doesn't know how to remove partition tables */ - sprintf(err, "Device %s already has a non-bcache superblock, " - "remove it using wipefs and wipefs -a\n", dev); - goto err; - } + die("Device %s already has a non-bcache superblock, " + "remove it using wipefs and wipefs -a\n", dev); return fd; - - err: - fprintf(stderr, "dev_open failed with: %s", err); - exit(EXIT_FAILURE); } -static unsigned min_bucket_size(int num_bucket_sizes, unsigned *bucket_sizes) -{ - int i; - unsigned min = bucket_sizes[0]; - - for (i = 0; i < num_bucket_sizes; i++) - min = bucket_sizes[i] < min ? bucket_sizes[i] : min; - - return min; -} - -void write_cache_sbs(int *fds, struct cache_sb *sb, - unsigned block_size, unsigned *bucket_sizes, - int num_bucket_sizes) -{ - char uuid_str[40], set_uuid_str[40]; - size_t i; - unsigned min_size = min_bucket_size(num_bucket_sizes, bucket_sizes); - - sb->offset = SB_SECTOR; - sb->version = BCACHE_SB_VERSION_CDEV_V3; - sb->magic = BCACHE_MAGIC; - sb->block_size = block_size; - sb->u64s = bch_journal_buckets_offset(sb); - - /* - * don't have a userspace crc32c implementation handy, just always use - * crc64 - */ - SET_CACHE_SB_CSUM_TYPE(sb, BCH_CSUM_CRC64); - - for (i = 0; i < sb->nr_in_set; i++) { - struct cache_member *m = sb->members + i; - - if (num_bucket_sizes <= 1) { - m->bucket_size = bucket_sizes[0]; - } else { - if (!bucket_sizes[i]) { - printf("No bucket size specified for cache %zu," - " using the default of %u", - i, bucket_sizes[0]); - m->bucket_size = bucket_sizes[0]; - } else { - m->bucket_size = bucket_sizes[i]; - } - } - - m->nbuckets = getblocks(fds[i]) / m->bucket_size; - m->first_bucket = (23 / m->bucket_size) + 1; - - if (m->nbuckets < 1 << 7) { - fprintf(stderr, "Not enough buckets: %llu, need %u\n", - m->nbuckets, 1 << 7); - exit(EXIT_FAILURE); - } - } - - for (i = 0; i < sb->nr_in_set; i++) { - struct cache_member *m = sb->members + i; - - SET_CACHE_BTREE_NODE_SIZE(sb, min_size); - - - sb->disk_uuid = m->uuid; - sb->nr_this_dev = i; - - sb->csum = csum_set(sb, CACHE_SB_CSUM_TYPE(sb)); - - uuid_unparse(sb->disk_uuid.b, uuid_str); - uuid_unparse(sb->user_uuid.b, set_uuid_str); - printf("UUID: %s\n" - "Set UUID: %s\n" - "version: %u\n" - "nbuckets: %llu\n" - "block_size: %u\n" - "bucket_size: %u\n" - "nr_in_set: %u\n" - "nr_this_dev: %u\n" - "first_bucket: %u\n", - uuid_str, set_uuid_str, - (unsigned) sb->version, - m->nbuckets, - sb->block_size, - m->bucket_size, - sb->nr_in_set, - sb->nr_this_dev, - m->first_bucket); - - do_write_sb(fds[i], sb); - } -} - -void next_cache_device(struct cache_sb *sb, - unsigned replication_set, - int tier, - unsigned replacement_policy, - bool discard) -{ - struct cache_member *m = sb->members + sb->nr_in_set; - - SET_CACHE_REPLICATION_SET(m, replication_set); - SET_CACHE_TIER(m, tier); - SET_CACHE_REPLACEMENT(m, replacement_policy); - SET_CACHE_DISCARD(m, discard); - uuid_generate(m->uuid.b); - - sb->nr_in_set++; -} - -unsigned get_blocksize(const char *path) +unsigned get_blocksize(const char *path, int fd) { struct stat statbuf; - if (stat(path, &statbuf)) { - fprintf(stderr, "Error statting %s: %s\n", - path, strerror(errno)); - exit(EXIT_FAILURE); - } + if (fstat(fd, &statbuf)) + die("Error statting %s: %s", path, strerror(errno)); if (S_ISBLK(statbuf.st_mode)) { /* check IO limits: @@ -714,17 +514,9 @@ unsigned get_blocksize(const char *path) * we want to use logical_block_size. */ unsigned int logical_block_size; - int fd = open(path, O_RDONLY); + if (ioctl(fd, BLKSSZGET, &logical_block_size)) + die("ioctl(%s, BLKSSZGET) failed: %m", path); - if (fd < 0) { - fprintf(stderr, "open(%s) failed: %m\n", path); - exit(EXIT_FAILURE); - } - if (ioctl(fd, BLKSSZGET, &logical_block_size)) { - fprintf(stderr, "ioctl(%s, BLKSSZGET) failed: %m\n", path); - exit(EXIT_FAILURE); - } - close(fd); return logical_block_size / 512; } @@ -738,10 +530,8 @@ long strtoul_or_die(const char *p, size_t max, const char *msg) { errno = 0; long v = strtol(p, NULL, 10); - if (errno || v < 0 || v >= max) { - fprintf(stderr, "Invalid %s %zi\n", msg, v); - exit(EXIT_FAILURE); - } + if (errno || v < 0 || v >= max) + die("Invalid %s %zi", msg, v); return v; } @@ -771,8 +561,7 @@ static void show_super_common(struct cache_sb *sb, bool force_csum) printf("ok\n"); } else { printf("bad magic\n"); - fprintf(stderr, "Invalid superblock (bad magic)\n"); - exit(2); + die("Invalid superblock (bad magic)"); } printf("sb.first_sector\t\t%ju", (uint64_t) sb->offset); @@ -780,8 +569,7 @@ static void show_super_common(struct cache_sb *sb, bool force_csum) printf(" [match]\n"); } else { printf(" [expected %ds]\n", SB_SECTOR); - fprintf(stderr, "Invalid superblock (bad sector)\n"); - exit(2); + die("Invalid superblock (bad sector)"); } printf("sb.csum\t\t\t%ju", (uint64_t) sb->csum); @@ -793,10 +581,8 @@ static void show_super_common(struct cache_sb *sb, bool force_csum) printf(" [match]\n"); } else { printf(" [expected %" PRIX64 "]\n", expected_csum); - if (force_csum) { - fprintf(stderr, "Corrupt superblock (bad csum)\n"); - exit(2); - } + if (force_csum) + die("Corrupt superblock (bad csum)"); } printf("sb.version\t\t%ju", (uint64_t) sb->version); @@ -835,6 +621,10 @@ static void show_super_common(struct cache_sb *sb, bool force_csum) uuid_unparse(sb->user_uuid.b, uuid); printf("cset.uuid\t\t%s\n", uuid); + + uuid_unparse(sb->set_uuid.b, uuid); + printf("internal.uuid\t%s\n", uuid); + } void show_super_backingdev(struct cache_sb *sb, bool force_csum) @@ -860,9 +650,13 @@ void show_super_backingdev(struct cache_sb *sb, bool force_csum) void show_super_cache(struct cache_sb *sb, bool force_csum) { struct cache_member *m = sb->members + sb->nr_this_dev; + char uuid[16]; show_super_common(sb, force_csum); + uuid_unparse(m->uuid.b, uuid); + printf("dev.cache.uuid\t%s\n", uuid); + printf("dev.sectors_per_block\t%u\n" "dev.sectors_per_bucket\t%u\n", sb->block_size, @@ -887,8 +681,6 @@ void show_super_cache(struct cache_sb *sb, bool force_csum) printf("cache.tier\t%llu\n", CACHE_TIER(m)); printf("cache.replication_set\t%llu\n", CACHE_REPLICATION_SET(m)); - printf("cache.cur_meta_replicas\t%llu\n", REPLICATION_SET_CUR_META_REPLICAS(m)); - printf("cache.cur_data_replicas\t%llu\n", REPLICATION_SET_CUR_DATA_REPLICAS(m)); printf("cache.has_metadata\t%llu\n", CACHE_HAS_METADATA(m)); printf("cache.has_data\t%llu\n", CACHE_HAS_DATA(m)); @@ -1000,55 +792,6 @@ char *dev_name(const char *ugly_path) { return strdup(buf); } -static void list_cacheset_devs(char *cset_dir, char *cset_name, bool parse_dev_name) -{ - DIR *cachedir, *dir; - struct stat cache_stat; - char entry[MAX_PATH]; - struct dirent *ent; - snprintf(entry, MAX_PATH, "%s/%s", cset_dir, cset_name); - - if((dir = opendir(entry)) != NULL) { - while((ent = readdir(dir)) != NULL) { - char buf[MAX_PATH]; - int len; - char *tmp; - - /* - * We are looking for all cache# directories - * do a strlen < 9 to skip over other entries - * that also start with "cache" - */ - if(strncmp(ent->d_name, "cache", 5) || - !(strlen(ent->d_name) < 9)) - continue; - - snprintf(entry, MAX_PATH, "%s/%s/%s", - cset_dir, - cset_name, - ent->d_name); - - if((cachedir = opendir(entry)) == NULL) - continue; - - if(stat(entry, &cache_stat)) - continue; - - if((len = readlink(entry, buf, sizeof(buf) - 1)) != - -1) { - buf[len] = '\0'; - if(parse_dev_name) { - tmp = dev_name(buf); - printf("/dev%s\n", tmp); - free(tmp); - } else { - printf("\t%s\n", buf); - } - } - } - } -} - char *find_matching_uuid(char *stats_dir, char *subdir, const char *stats_dev_uuid) { /* Do a query-dev --uuid only to get the uuid @@ -1121,373 +864,21 @@ char *find_matching_uuid(char *stats_dir, char *subdir, const char *stats_dev_uu return err; } -char *list_cachesets(char *cset_dir, bool list_devs) +int bcachectl_open(void) { - struct dirent *ent; - DIR *dir; - char *err = NULL; - - dir = opendir(cset_dir); - if (!dir) { - err = "Failed to open cacheset dir"; - goto err; - } - - while ((ent = readdir(dir)) != NULL) { - struct stat statbuf; - char entry[MAX_PATH]; - - if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) - continue; - - snprintf(entry, MAX_PATH, "%s/%s", cset_dir, ent->d_name); - if(stat(entry, &statbuf) == -1) { - err = "Failed to stat cacheset subdir"; - goto err; - } + int fd = open("/dev/bcache-ctl", O_RDWR); + if (fd < 0) + die("Can't open bcache device: %s", strerror(errno)); - if (S_ISDIR(statbuf.st_mode)) { - printf("%s\n", ent->d_name); - - if(list_devs) { - list_cacheset_devs(cset_dir, ent->d_name, true); - } - } - } - -err: - closedir(dir); - return err; -} - -char *register_bcache(char *const *devs) -{ - int ret, bcachefd; - char *err = NULL; - - bcachefd = open("/dev/bcache", O_RDWR); - if (bcachefd < 0) { - err = "Can't open bcache device"; - goto err; - } - - ret = ioctl(bcachefd, BCH_IOCTL_REGISTER, devs); - if (ret < 0) { - char tmp[64]; - snprintf(tmp, 64, "ioctl register error: %s\n", - strerror(ret)); - err = strdup(tmp); - goto err; - } - -err: - if (bcachefd) - close(bcachefd); - return err; -} - -char *unregister_bcache(char *const *devs) -{ - int ret, bcachefd; - char *err = NULL; - - bcachefd = open("/dev/bcache_extent0", O_RDWR); - if (bcachefd < 0) { - err = "Can't open bcache device"; - goto err; - } - - ret = ioctl(bcachefd, BCH_IOCTL_STOP); - if (ret < 0) { - char tmp[64]; - snprintf(tmp, 64, "ioctl unregister error: %s\n", - strerror(ret)); - err = strdup(tmp); - goto err; - } - -err: - close(bcachefd); - return err; -} - -char *add_devices(char *const *devs) -{ - int ret, bcachefd; - char *err = NULL; - - bcachefd = open("/dev/bcache_extent0", O_RDWR); - if (bcachefd < 0) { - err = "Can't open bcache device"; - goto err; - } - - struct bch_ioctl_add_disks ia; - ia.devs = devs; - - ret = ioctl(bcachefd, BCH_IOCTL_ADD_DISKS, &ia); - if (ret < 0) { - char tmp[128]; - snprintf(tmp, 128, "ioctl add disk error: %s\n", - strerror(ret)); - err = strdup(tmp); - } - -err: - close(bcachefd); - return err; -} - -char *remove_device(const char *dev, bool force) -{ - int ret, bcachefd; - char *err = NULL; - - bcachefd = open("/dev/bcache_extent0", O_RDWR); - if (bcachefd < 0) { - err = "Can't open bcache device"; - goto err; - } - - struct bch_ioctl_rm_disk ir; - ir.dev = dev; - ir.force = force ? 1 : 0; - - ret = ioctl(bcachefd, BCH_IOCTL_RM_DISK, &ir); - if (ret < 0) { - char tmp[128]; - snprintf(tmp, 128, "ioctl add disk error: %s\n", - strerror(ret)); - err = strdup(tmp); - } - -err: - close(bcachefd); - return err; -} - -char *device_set_failed(const char *dev_uuid) { - int ret, bcachefd; - char *err = NULL; - uuid_le dev; - struct bch_ioctl_disk_failed df; - - bcachefd = open("/dev/bcache_extent0", O_RDWR); - if (bcachefd < 0) { - err = "Can't open bcache device"; - goto err; - } - - uuid_parse(dev_uuid, dev.b); - df.dev_uuid = dev; - - ret = ioctl(bcachefd, BCH_IOCTL_SET_DISK_FAILED, &df); - if (ret < 0) { - char tmp[128]; - snprintf(tmp, 128, "ioctl set disk failed error %s\n", - strerror(ret)); - err = strdup(tmp); - } - -err: - close(bcachefd); - return err; -} - -char *probe(char *dev, int udev) -{ - struct cache_sb sb; - char uuid[40]; - blkid_probe pr; - char *err = NULL; - - int fd = open(dev, O_RDONLY); - if (fd == -1) { - err = "Got file descriptor -1 trying to open dev"; - goto err; - } - - if (!(pr = blkid_new_probe())) { - err = "Failed trying to get a blkid for new probe"; - goto err; - } - - if (blkid_probe_set_device(pr, fd, 0, 0)) { - err = "Failed blkid probe set device"; - goto err; - } - - /* probe partitions too */ - if (blkid_probe_enable_partitions(pr, true)) { - err = "Enable probe partitions"; - goto err; - } - - /* bail if anything was found - * probe-bcache isn't needed once blkid recognizes bcache */ - if (!blkid_do_probe(pr)) { - err = "blkid recognizes bcache"; - goto err; - } - - if (pread(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) { - err = "Failed to read superblock"; - goto err; - } - - if (memcmp(&sb.magic, &BCACHE_MAGIC, sizeof(sb.magic))) { - err = "Bcache magic incorrect"; - goto err; - } - - uuid_unparse(sb.disk_uuid.b, uuid); - - if (udev) - printf("ID_FS_UUID=%s\n" - "ID_FS_UUID_ENC=%s\n" - "ID_FS_TYPE=bcache\n", - uuid, uuid); - else - printf("%s: UUID=\"\" TYPE=\"bcache\"\n", uuid); - - return 0; - -err: - return err; + return fd; } -char *read_stat_dir(DIR *dir, char *stats_dir, char *stat_name, char *ret) +unsigned nr_args(char *const *args) { - struct stat statbuf; - char entry[MAX_PATH]; - char *err = NULL; - - snprintf(entry, MAX_PATH, "%s/%s", stats_dir, stat_name); - if(stat(entry, &statbuf) == -1) { - char tmp[MAX_PATH]; - snprintf(tmp, MAX_PATH, "Failed to stat %s\n", entry); - err = strdup(tmp); - goto err; - } - - if (S_ISREG(statbuf.st_mode)) { - FILE *fp = NULL; + unsigned i; - fp = fopen(entry, "r"); - if(!fp) { - /* If we can't open the file, this is probably because - * of permissions, just move to the next file */ - return NULL; - } + for (i = 0; args[i]; i++) + ; - while(fgets(ret, MAX_PATH, fp)); - fclose(fp); - } -err: - return err; -} - -char *bcache_get_capacity(const char *cset_dir, const char *capacity_uuid, - bool show_devs) -{ - char *err = NULL; - char bucket_size_path[MAX_PATH]; - char nbuckets_path[MAX_PATH]; - char avail_buckets_path[MAX_PATH]; - char cache_path[MAX_PATH]; - - double bucket_sizes[MAX_DEVS]; - double nbuckets[MAX_DEVS]; - double avail_buckets[MAX_DEVS]; - char *dev_names[MAX_DEVS]; - int dev_count = 0, i; - char intbuf[4]; - double total_cap = 0, total_free = 0; - int precision = 2; - - snprintf(bucket_size_path, MAX_PATH, "%s/%s/%s/%s", cset_dir, - capacity_uuid, "cache0", "bucket_size_bytes"); - snprintf(nbuckets_path, MAX_PATH, "%s/%s/%s/%s", cset_dir, - capacity_uuid, "cache0", "nbuckets"); - snprintf(avail_buckets_path, MAX_PATH, "%s/%s/%s/%s", cset_dir, - capacity_uuid, "cache0", "available_buckets"); - snprintf(cache_path, MAX_PATH, "%s/%s/%s", cset_dir, capacity_uuid, - "cache0"); - - while (true) { - char buf[MAX_PATH]; - int len; - DIR *cache_dir; - - if((cache_dir = opendir(cache_path)) == NULL) - break; - - err = read_stat_dir(cache_dir, cache_path, - "bucket_size_bytes", buf); - if (err) - goto err; - else - bucket_sizes[dev_count] = atof(buf); - - err = read_stat_dir(cache_dir, cache_path, - "nbuckets", buf); - if (err) - goto err; - else - nbuckets[dev_count] = atof(buf); - - err = read_stat_dir(cache_dir, cache_path, - "available_buckets", buf); - if (err) - goto err; - else - avail_buckets[dev_count] = atof(buf); - - if((len = readlink(cache_path, buf, sizeof(buf) - 1)) != -1) { - buf[len] = '\0'; - dev_names[dev_count] = dev_name(buf); - } - - snprintf(intbuf, 4, "%d", dev_count); - - /* remove i/stat and append i++/stat */ - bucket_size_path[strlen(cache_path) - strlen(intbuf)] = 0; - nbuckets_path[strlen(cache_path) - strlen(intbuf)] = 0; - avail_buckets_path[strlen(cache_path) - strlen(intbuf)] = 0; - cache_path[strlen(cache_path) - strlen(intbuf)] = 0; - - dev_count++; - - strcat(cache_path, intbuf); - strcat(bucket_size_path, intbuf); - strcat(nbuckets_path, intbuf); - strcat(avail_buckets_path, intbuf); - } - - printf("%-15s%-25s%-25s\n", "Device Name", "Capacity (512 Blocks)", "Free (512 Blocks)"); - - if (show_devs) { - for (i = 0; i < dev_count; i++) { - printf("%s%-11s%-25.*f%-25.*f\n", "/dev", dev_names[i], - precision, - (bucket_sizes[i] * nbuckets[i]) / 512, - precision, - (bucket_sizes[i] * avail_buckets[i]) / 512); - } - } - - for (i = 0; i < dev_count; i++) { - total_cap += (bucket_sizes[i] * nbuckets[i]) / 512; - total_free += (bucket_sizes[i] * avail_buckets[i]) / 512; - - } - - printf("%-15s%-25.*f%-25.*f\n", "Total", precision, total_cap, - precision, total_free); - -err: - for (i = 0; i < dev_count; i++) - if (dev_names[i]) - free(dev_names[i]); - return err; + return i; }