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