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