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