1/*- 2 * Copyright (c) 2010-2012 Semihalf. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD$"); 29 30#include <assert.h> 31#include <stdarg.h> 32#include <stdio.h> 33#include <stdlib.h> 34#include <unistd.h> 35#include <string.h> 36#include <fcntl.h> 37#include <errno.h> 38#include <sys/ioctl.h> 39#include <sys/stat.h> 40#include <sys/param.h> 41#include <sys/stdint.h> 42#include <sys/ucred.h> 43#include <sys/disk.h> 44#include <sys/mount.h> 45 46#include <fs/nandfs/nandfs_fs.h> 47#include <libnandfs.h> 48 49#define NANDFS_IS_VALID 0x1 50#define NANDFS_IS_OPENED 0x2 51#define NANDFS_IS_OPENED_DEV 0x4 52#define NANDFS_IS_ERROR 0x8 53 54#define DEBUG 55#undef DEBUG 56#ifdef DEBUG 57#define NANDFS_DEBUG(fmt, args...) do { \ 58 printf("libnandfs:" fmt "\n", ##args); } while (0) 59#else 60#define NANDFS_DEBUG(fmt, args...) 61#endif 62 63#define NANDFS_ASSERT_VALID(fs) assert((fs)->n_flags & NANDFS_IS_VALID) 64#define NANDFS_ASSERT_VALID_DEV(fs) \ 65 assert(((fs)->n_flags & (NANDFS_IS_VALID | NANDFS_IS_OPENED_DEV)) == \ 66 (NANDFS_IS_VALID | NANDFS_IS_OPENED_DEV)) 67 68int 69nandfs_iserror(struct nandfs *fs) 70{ 71 72 NANDFS_ASSERT_VALID(fs); 73 74 return (fs->n_flags & NANDFS_IS_ERROR); 75} 76 77const char * 78nandfs_errmsg(struct nandfs *fs) 79{ 80 81 NANDFS_ASSERT_VALID(fs); 82 83 assert(nandfs_iserror(fs)); 84 assert(fs->n_errmsg); 85 return (fs->n_errmsg); 86} 87 88static void 89nandfs_seterr(struct nandfs *fs, const char *fmt, ...) 90{ 91 va_list ap; 92 93 va_start(ap, fmt); 94 vsnprintf(fs->n_errmsg, sizeof(fs->n_errmsg), fmt, ap); 95 va_end(ap); 96 fs->n_flags |= NANDFS_IS_ERROR; 97} 98 99const char * 100nandfs_dev(struct nandfs *fs) 101{ 102 103 NANDFS_ASSERT_VALID(fs); 104 return (fs->n_dev); 105} 106 107void 108nandfs_init(struct nandfs *fs, const char *dir) 109{ 110 111 snprintf(fs->n_ioc, sizeof(fs->n_ioc), "%s/%s", dir, "."); 112 fs->n_iocfd = -1; 113 fs->n_flags = NANDFS_IS_VALID; 114} 115 116void 117nandfs_destroy(struct nandfs *fs) 118{ 119 120 assert(fs->n_iocfd == -1); 121 fs->n_flags &= 122 ~(NANDFS_IS_ERROR | NANDFS_IS_VALID); 123 assert(fs->n_flags == 0); 124} 125 126int 127nandfs_open(struct nandfs *fs) 128{ 129 struct nandfs_fsinfo fsinfo; 130 131 fs->n_flags |= NANDFS_IS_OPENED; 132 133 fs->n_iocfd = open(fs->n_ioc, O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | 134 S_IWGRP | S_IROTH | S_IWOTH); 135 if (fs->n_iocfd == -1) { 136 nandfs_seterr(fs, "couldn't open %s: %s", fs->n_ioc, 137 strerror(errno)); 138 return (-1); 139 } 140 141 if (ioctl(fs->n_iocfd, NANDFS_IOCTL_GET_FSINFO, &fsinfo) == -1) { 142 nandfs_seterr(fs, "couldn't fetch fsinfo: %s", 143 strerror(errno)); 144 return (-1); 145 } 146 147 memcpy(&fs->n_fsdata, &fsinfo.fs_fsdata, sizeof(fs->n_fsdata)); 148 memcpy(&fs->n_sb, &fsinfo.fs_super, sizeof(fs->n_sb)); 149 snprintf(fs->n_dev, sizeof(fs->n_dev), "%s", fsinfo.fs_dev); 150 151 return (0); 152} 153 154void 155nandfs_close(struct nandfs *fs) 156{ 157 158 NANDFS_ASSERT_VALID(fs); 159 assert(fs->n_flags & NANDFS_IS_OPENED); 160 161 close(fs->n_iocfd); 162 fs->n_iocfd = -1; 163 fs->n_flags &= ~NANDFS_IS_OPENED; 164} 165 166int 167nandfs_get_cpstat(struct nandfs *fs, struct nandfs_cpstat *cpstat) 168{ 169 170 NANDFS_ASSERT_VALID(fs); 171 172 if (ioctl(fs->n_iocfd, NANDFS_IOCTL_GET_CPSTAT, cpstat) == -1) { 173 nandfs_seterr(fs, "ioctl NANDFS_IOCTL_GET_CPSTAT: %s", 174 strerror(errno)); 175 return (-1); 176 } 177 178 return (0); 179} 180 181static ssize_t 182nandfs_get_cpinfo(struct nandfs *fs, uint64_t cno, int mode, 183 struct nandfs_cpinfo *cpinfo, size_t nci) 184{ 185 struct nandfs_argv args; 186 187 NANDFS_ASSERT_VALID(fs); 188 189 args.nv_base = (u_long)cpinfo; 190 args.nv_nmembs = nci; 191 args.nv_index = cno; 192 args.nv_flags = mode; 193 194 if (ioctl(fs->n_iocfd, NANDFS_IOCTL_GET_CPINFO, &args) == -1) { 195 nandfs_seterr(fs, "ioctl NANDFS_IOCTL_GET_CPINFO: %s", 196 strerror(errno)); 197 return (-1); 198 } 199 200 return (args.nv_nmembs); 201} 202 203ssize_t 204nandfs_get_cp(struct nandfs *fs, uint64_t cno, struct nandfs_cpinfo *cpinfo, 205 size_t nci) 206{ 207 208 return (nandfs_get_cpinfo(fs, cno, NANDFS_CHECKPOINT, cpinfo, nci)); 209} 210 211ssize_t 212nandfs_get_snap(struct nandfs *fs, uint64_t cno, struct nandfs_cpinfo *cpinfo, 213 size_t nci) 214{ 215 216 return (nandfs_get_cpinfo(fs, cno, NANDFS_SNAPSHOT, cpinfo, nci)); 217} 218 219int 220nandfs_make_snap(struct nandfs *fs, uint64_t *cno) 221{ 222 223 NANDFS_ASSERT_VALID(fs); 224 225 if (ioctl(fs->n_iocfd, NANDFS_IOCTL_MAKE_SNAP, cno) == -1) { 226 nandfs_seterr(fs, "ioctl NANDFS_IOCTL_MAKE_SNAP: %s", 227 strerror(errno)); 228 return (-1); 229 } 230 231 return (0); 232} 233 234int 235nandfs_delete_snap(struct nandfs *fs, uint64_t cno) 236{ 237 238 NANDFS_ASSERT_VALID(fs); 239 240 if (ioctl(fs->n_iocfd, NANDFS_IOCTL_DELETE_SNAP, &cno) == -1) { 241 nandfs_seterr(fs, "ioctl NANDFS_IOCTL_DELETE_SNAP: %s", 242 strerror(errno)); 243 return (-1); 244 } 245 246 return (0); 247} 248