1235537Sgber/*- 2235537Sgber * Copyright (c) 2010-2012 Semihalf. 3235537Sgber * All rights reserved. 4235537Sgber * 5235537Sgber * Redistribution and use in source and binary forms, with or without 6235537Sgber * modification, are permitted provided that the following conditions 7235537Sgber * are met: 8235537Sgber * 1. Redistributions of source code must retain the above copyright 9235537Sgber * notice, this list of conditions and the following disclaimer. 10235537Sgber * 2. Redistributions in binary form must reproduce the above copyright 11235537Sgber * notice, this list of conditions and the following disclaimer in the 12235537Sgber * documentation and/or other materials provided with the distribution. 13235537Sgber * 14235537Sgber * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15235537Sgber * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16235537Sgber * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17235537Sgber * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18235537Sgber * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19235537Sgber * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20235537Sgber * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21235537Sgber * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22235537Sgber * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23235537Sgber * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24235537Sgber * SUCH DAMAGE. 25235537Sgber */ 26235537Sgber 27235537Sgber#include <sys/cdefs.h> 28235537Sgber__FBSDID("$FreeBSD$"); 29235537Sgber 30235537Sgber#include <assert.h> 31235537Sgber#include <stdarg.h> 32235537Sgber#include <stdio.h> 33235537Sgber#include <stdlib.h> 34235537Sgber#include <unistd.h> 35235537Sgber#include <string.h> 36235537Sgber#include <fcntl.h> 37235537Sgber#include <errno.h> 38235537Sgber#include <sys/ioctl.h> 39235537Sgber#include <sys/stat.h> 40235537Sgber#include <sys/param.h> 41235537Sgber#include <sys/stdint.h> 42235537Sgber#include <sys/ucred.h> 43235537Sgber#include <sys/disk.h> 44235537Sgber#include <sys/mount.h> 45235537Sgber 46235537Sgber#include <fs/nandfs/nandfs_fs.h> 47235537Sgber#include <libnandfs.h> 48235537Sgber 49235537Sgber#define NANDFS_IS_VALID 0x1 50235537Sgber#define NANDFS_IS_OPENED 0x2 51235537Sgber#define NANDFS_IS_OPENED_DEV 0x4 52235537Sgber#define NANDFS_IS_ERROR 0x8 53235537Sgber 54235537Sgber#define DEBUG 55235537Sgber#undef DEBUG 56235537Sgber#ifdef DEBUG 57235537Sgber#define NANDFS_DEBUG(fmt, args...) do { \ 58235537Sgber printf("libnandfs:" fmt "\n", ##args); } while (0) 59235537Sgber#else 60235537Sgber#define NANDFS_DEBUG(fmt, args...) 61235537Sgber#endif 62235537Sgber 63235537Sgber#define NANDFS_ASSERT_VALID(fs) assert((fs)->n_flags & NANDFS_IS_VALID) 64235537Sgber#define NANDFS_ASSERT_VALID_DEV(fs) \ 65235537Sgber assert(((fs)->n_flags & (NANDFS_IS_VALID | NANDFS_IS_OPENED_DEV)) == \ 66235537Sgber (NANDFS_IS_VALID | NANDFS_IS_OPENED_DEV)) 67235537Sgber 68235537Sgberint 69235537Sgbernandfs_iserror(struct nandfs *fs) 70235537Sgber{ 71235537Sgber 72235537Sgber NANDFS_ASSERT_VALID(fs); 73235537Sgber 74235537Sgber return (fs->n_flags & NANDFS_IS_ERROR); 75235537Sgber} 76235537Sgber 77235537Sgberconst char * 78235537Sgbernandfs_errmsg(struct nandfs *fs) 79235537Sgber{ 80235537Sgber 81235537Sgber NANDFS_ASSERT_VALID(fs); 82235537Sgber 83235537Sgber assert(nandfs_iserror(fs)); 84235537Sgber assert(fs->n_errmsg); 85235537Sgber return (fs->n_errmsg); 86235537Sgber} 87235537Sgber 88235537Sgberstatic void 89235537Sgbernandfs_seterr(struct nandfs *fs, const char *fmt, ...) 90235537Sgber{ 91235537Sgber va_list ap; 92235537Sgber 93235537Sgber va_start(ap, fmt); 94235537Sgber vsnprintf(fs->n_errmsg, sizeof(fs->n_errmsg), fmt, ap); 95235537Sgber va_end(ap); 96235537Sgber fs->n_flags |= NANDFS_IS_ERROR; 97235537Sgber} 98235537Sgber 99235537Sgberconst char * 100235537Sgbernandfs_dev(struct nandfs *fs) 101235537Sgber{ 102235537Sgber 103235537Sgber NANDFS_ASSERT_VALID(fs); 104235537Sgber return (fs->n_dev); 105235537Sgber} 106235537Sgber 107235537Sgbervoid 108235537Sgbernandfs_init(struct nandfs *fs, const char *dir) 109235537Sgber{ 110235537Sgber 111235537Sgber snprintf(fs->n_ioc, sizeof(fs->n_ioc), "%s/%s", dir, "."); 112235537Sgber fs->n_iocfd = -1; 113235537Sgber fs->n_flags = NANDFS_IS_VALID; 114235537Sgber} 115235537Sgber 116235537Sgbervoid 117235537Sgbernandfs_destroy(struct nandfs *fs) 118235537Sgber{ 119235537Sgber 120235537Sgber assert(fs->n_iocfd == -1); 121235537Sgber fs->n_flags &= 122235537Sgber ~(NANDFS_IS_ERROR | NANDFS_IS_VALID); 123235537Sgber assert(fs->n_flags == 0); 124235537Sgber} 125235537Sgber 126235537Sgberint 127235537Sgbernandfs_open(struct nandfs *fs) 128235537Sgber{ 129235537Sgber struct nandfs_fsinfo fsinfo; 130235537Sgber 131235537Sgber fs->n_flags |= NANDFS_IS_OPENED; 132235537Sgber 133235537Sgber fs->n_iocfd = open(fs->n_ioc, O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | 134235537Sgber S_IWGRP | S_IROTH | S_IWOTH); 135235537Sgber if (fs->n_iocfd == -1) { 136235537Sgber nandfs_seterr(fs, "couldn't open %s: %s", fs->n_ioc, 137235537Sgber strerror(errno)); 138235537Sgber return (-1); 139235537Sgber } 140235537Sgber 141235537Sgber if (ioctl(fs->n_iocfd, NANDFS_IOCTL_GET_FSINFO, &fsinfo) == -1) { 142235537Sgber nandfs_seterr(fs, "couldn't fetch fsinfo: %s", 143235537Sgber strerror(errno)); 144235537Sgber return (-1); 145235537Sgber } 146235537Sgber 147235537Sgber memcpy(&fs->n_fsdata, &fsinfo.fs_fsdata, sizeof(fs->n_fsdata)); 148235537Sgber memcpy(&fs->n_sb, &fsinfo.fs_super, sizeof(fs->n_sb)); 149235537Sgber snprintf(fs->n_dev, sizeof(fs->n_dev), "%s", fsinfo.fs_dev); 150235537Sgber 151235537Sgber return (0); 152235537Sgber} 153235537Sgber 154235537Sgbervoid 155235537Sgbernandfs_close(struct nandfs *fs) 156235537Sgber{ 157235537Sgber 158235537Sgber NANDFS_ASSERT_VALID(fs); 159235537Sgber assert(fs->n_flags & NANDFS_IS_OPENED); 160235537Sgber 161235537Sgber close(fs->n_iocfd); 162235537Sgber fs->n_iocfd = -1; 163235537Sgber fs->n_flags &= ~NANDFS_IS_OPENED; 164235537Sgber} 165235537Sgber 166235537Sgberint 167235537Sgbernandfs_get_cpstat(struct nandfs *fs, struct nandfs_cpstat *cpstat) 168235537Sgber{ 169235537Sgber 170235537Sgber NANDFS_ASSERT_VALID(fs); 171235537Sgber 172235537Sgber if (ioctl(fs->n_iocfd, NANDFS_IOCTL_GET_CPSTAT, cpstat) == -1) { 173235537Sgber nandfs_seterr(fs, "ioctl NANDFS_IOCTL_GET_CPSTAT: %s", 174235537Sgber strerror(errno)); 175235537Sgber return (-1); 176235537Sgber } 177235537Sgber 178235537Sgber return (0); 179235537Sgber} 180235537Sgber 181235537Sgberstatic ssize_t 182235537Sgbernandfs_get_cpinfo(struct nandfs *fs, uint64_t cno, int mode, 183235537Sgber struct nandfs_cpinfo *cpinfo, size_t nci) 184235537Sgber{ 185235537Sgber struct nandfs_argv args; 186235537Sgber 187235537Sgber NANDFS_ASSERT_VALID(fs); 188235537Sgber 189235537Sgber args.nv_base = (u_long)cpinfo; 190235537Sgber args.nv_nmembs = nci; 191235537Sgber args.nv_index = cno; 192235537Sgber args.nv_flags = mode; 193235537Sgber 194235537Sgber if (ioctl(fs->n_iocfd, NANDFS_IOCTL_GET_CPINFO, &args) == -1) { 195235537Sgber nandfs_seterr(fs, "ioctl NANDFS_IOCTL_GET_CPINFO: %s", 196235537Sgber strerror(errno)); 197235537Sgber return (-1); 198235537Sgber } 199235537Sgber 200235537Sgber return (args.nv_nmembs); 201235537Sgber} 202235537Sgber 203235537Sgberssize_t 204235537Sgbernandfs_get_cp(struct nandfs *fs, uint64_t cno, struct nandfs_cpinfo *cpinfo, 205235537Sgber size_t nci) 206235537Sgber{ 207235537Sgber 208235537Sgber return (nandfs_get_cpinfo(fs, cno, NANDFS_CHECKPOINT, cpinfo, nci)); 209235537Sgber} 210235537Sgber 211235537Sgberssize_t 212235537Sgbernandfs_get_snap(struct nandfs *fs, uint64_t cno, struct nandfs_cpinfo *cpinfo, 213235537Sgber size_t nci) 214235537Sgber{ 215235537Sgber 216235537Sgber return (nandfs_get_cpinfo(fs, cno, NANDFS_SNAPSHOT, cpinfo, nci)); 217235537Sgber} 218235537Sgber 219235537Sgberint 220235537Sgbernandfs_make_snap(struct nandfs *fs, uint64_t *cno) 221235537Sgber{ 222235537Sgber 223235537Sgber NANDFS_ASSERT_VALID(fs); 224235537Sgber 225235537Sgber if (ioctl(fs->n_iocfd, NANDFS_IOCTL_MAKE_SNAP, cno) == -1) { 226235537Sgber nandfs_seterr(fs, "ioctl NANDFS_IOCTL_MAKE_SNAP: %s", 227235537Sgber strerror(errno)); 228235537Sgber return (-1); 229235537Sgber } 230235537Sgber 231235537Sgber return (0); 232235537Sgber} 233235537Sgber 234235537Sgberint 235235537Sgbernandfs_delete_snap(struct nandfs *fs, uint64_t cno) 236235537Sgber{ 237235537Sgber 238235537Sgber NANDFS_ASSERT_VALID(fs); 239235537Sgber 240235537Sgber if (ioctl(fs->n_iocfd, NANDFS_IOCTL_DELETE_SNAP, &cno) == -1) { 241235537Sgber nandfs_seterr(fs, "ioctl NANDFS_IOCTL_DELETE_SNAP: %s", 242235537Sgber strerror(errno)); 243235537Sgber return (-1); 244235537Sgber } 245235537Sgber 246235537Sgber return (0); 247235537Sgber} 248