xref: /netbsd-src/usr.sbin/fssconfig/fssconfig.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: fssconfig.c,v 1.5 2005/04/17 16:28:26 hannken Exp $	*/
2 
3 /*-
4  * Copyright (c) 2003 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Juergen Hannken-Illjes.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <sys/param.h>
40 #include <sys/ioctl.h>
41 #include <sys/mount.h>
42 #include <sys/stat.h>
43 
44 #include <err.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <time.h>
50 #include <unistd.h>
51 #include <util.h>
52 
53 #include <dev/fssvar.h>
54 
55 int	vflag = 0;
56 int	xflag = 0;
57 
58 void	config(int, char **);
59 void	unconfig(int, char **);
60 void	list(int, char **);
61 void	usage(void);
62 
63 int
64 main(int argc, char **argv)
65 {
66 	int ch;
67 	void (*action)(int, char **);
68 
69 	action = config;
70 
71 	while ((ch = getopt(argc, argv, "cluvx")) != -1) {
72 		switch (ch) {
73 		case 'c':
74 			action = config;
75 			break;
76 		case 'l':
77 			action = list;
78 			break;
79 		case 'u':
80 			action = unconfig;
81 			break;
82 		case 'v':
83 			vflag++;
84 			break;
85 		case 'x':
86 			xflag++;
87 			break;
88 		default:
89 		case '?':
90 			usage();
91 			/* NOTREACHED */
92 		}
93 	}
94 
95 	argc -= optind;
96 	argv += optind;
97 
98 	(*action)(argc, argv);
99 
100 	exit(0);
101 }
102 
103 void
104 config(int argc, char **argv)
105 {
106 	int fd, isreg, istmp, ispersistent;
107 	char full[64], path[MAXPATHLEN];
108 	off_t bssize;
109 	dev_t mountdev;
110 	struct stat sbuf;
111 	struct statvfs fsbuf;
112 	struct fss_set fss;
113 
114 	if (argc < 3)
115 		usage();
116 
117 	istmp = ispersistent = 0;
118 
119 	fss.fss_mount = argv[1];
120 	fss.fss_bstore = argv[2];
121 
122 	if (statvfs(argv[1], &fsbuf) != 0 || stat(argv[1], &sbuf) != 0)
123 		err(1, "stat %s", argv[1]);
124 	mountdev = sbuf.st_dev;
125 	if (stat(argv[2], &sbuf) == 0 &&
126 	    S_ISREG(sbuf.st_mode) &&
127 	    sbuf.st_dev == mountdev) {
128 		if ((sbuf.st_flags & SF_SNAPSHOT) == 0)
129 			errx(1, "%s: exists and is not a snapshot", argv[2]);
130 		if (argc != 3)
131 			usage();
132 		isreg = ispersistent = 1;
133 
134 		goto configure;
135 	}
136 
137 	if (argc > 5)
138 		usage();
139 
140 	if (argc > 3)
141 		fss.fss_csize = strsuftoll("cluster size", argv[3], 0, INT_MAX);
142 	else
143 		fss.fss_csize = 0;
144 	if (argc > 4)
145 		bssize = strsuftoll("bs size", argv[4], 0, LLONG_MAX);
146 	else
147 		bssize = (off_t)fsbuf.f_blocks*fsbuf.f_frsize;
148 
149 	/*
150 	 * Create the backing store. If it is a directory, create a temporary
151 	 * file and set the unlink flag.
152 	 */
153 	if ((fd = open(fss.fss_bstore, O_CREAT|O_TRUNC|O_WRONLY, 0600)) < 0) {
154 		if (errno != EISDIR)
155 			err(1, "create: %s", fss.fss_bstore);
156 		snprintf(path, sizeof(path), "%s/XXXXXXXXXX", fss.fss_bstore);
157 		if ((fd = mkstemp(path)) < 0)
158 			err(1, "mkstemp: %s", path);
159 		fss.fss_bstore = path;
160 		istmp = 1;
161 	}
162 	if (fstat(fd, &sbuf) < 0)
163 		err(1, "stat: %s", fss.fss_bstore);
164 	if (!ispersistent && sbuf.st_dev == mountdev)
165 		ispersistent = 1;
166 	isreg = S_ISREG(sbuf.st_mode);
167 	if (!ispersistent && isreg && ftruncate(fd, bssize) < 0)
168 		err(1, "truncate %s", fss.fss_bstore);
169 	close(fd);
170 
171 configure:
172 	if ((fd = opendisk(argv[0], O_RDWR, full, sizeof(full), 0)) < 0) {
173 		if (istmp)
174 			unlink(fss.fss_bstore);
175 		err(1, "open: %s", argv[0]);
176 	}
177 
178 	if (ioctl(fd, FSSIOCSET, &fss) < 0) {
179 		if (istmp)
180 			unlink(fss.fss_bstore);
181 		err(1, "%s: FSSIOCSET", full);
182 	}
183 
184 	if ((xflag || istmp) && isreg && unlink(fss.fss_bstore) < 0)
185 		err(1, "unlink: %s", fss.fss_bstore);
186 
187 	if (vflag)
188 		list(1, argv);
189 }
190 
191 void
192 unconfig(int argc, char **argv)
193 {
194 	int fd;
195 	char full[64];
196 
197 	if (argc != 1)
198 		usage();
199 
200 	if (vflag)
201 		list(1, argv);
202 
203 	if ((fd = opendisk(argv[0], O_RDWR, full, sizeof(full), 0)) < 0)
204 		err(1, "open: %s", argv[0]);
205 
206 	if (ioctl(fd, FSSIOCCLR) < 0)
207 		err(1, "%s: FSSIOCCLR", full);
208 }
209 
210 void
211 list(int argc, char **argv)
212 {
213 	int n, fd, flags;
214 	char *dev, path[64], full[64];
215 	char clbuf[5], bsbuf[5], tmbuf[64];
216 	time_t t;
217 	struct fss_get fsg;
218 
219 	if (argc > 1)
220 		usage();
221 
222 	if (argc > 0)
223 		dev = argv[0];
224 	else
225 		dev = path;
226 
227 	for (n = 0; ; n++) {
228 		if (argc == 0)
229 			snprintf(path, sizeof(path), "fss%d", n);
230 		if ((fd = opendisk(dev, O_RDONLY, full, sizeof(full), 0)) < 0) {
231 			if (argc == 0 && (errno == ENOENT || errno == ENXIO))
232 				break;
233 			err(1, "open: %s", dev);
234 		}
235 
236 		if (ioctl(fd, FSSIOFGET, &flags) < 0)
237 			flags = 0;
238 
239 		if (ioctl(fd, FSSIOCGET, &fsg) < 0) {
240 			if (errno == ENXIO)
241 				printf("%s: not in use\n", dev);
242 			else
243 				err(1, "%s: FSSIOCGET", full);
244 		} else if (vflag) {
245 			humanize_number(clbuf, sizeof(clbuf),
246 			    (int64_t)fsg.fsg_csize,
247 			    "", HN_AUTOSCALE, HN_B|HN_NOSPACE);
248 
249 			humanize_number(bsbuf, sizeof(bsbuf),
250 			    (int64_t)fsg.fsg_bs_size*fsg.fsg_csize,
251 			    "", HN_AUTOSCALE, HN_B|HN_NOSPACE);
252 
253 			t = fsg.fsg_time.tv_sec;
254 			strftime(tmbuf, sizeof(tmbuf), "%F %T", localtime(&t));
255 
256 			printf("%s: %s, taken %s", dev, fsg.fsg_mount, tmbuf);
257 			if ((flags & FSS_UNCONFIG_ON_CLOSE) != 0)
258 				printf(", unconfig on close");
259 			if (fsg.fsg_csize == 0)
260 				printf(", file system internal\n");
261 			else
262 				printf(", %"PRId64" cluster of %s, %s backup\n",
263 				    fsg.fsg_mount_size, clbuf, bsbuf);
264 		} else
265 			printf("%s: %s\n", dev, fsg.fsg_mount);
266 
267 		close(fd);
268 
269 		if (argc > 0)
270 			break;
271 	}
272 }
273 
274 void
275 usage(void)
276 {
277 	fprintf(stderr, "%s",
278 	    "usage: fssconfig [-cxv] device path backup [cluster [size]]\n"
279 	    "       fssconfig -u [-v] device\n"
280 	    "       fssconfig -l [-v] [device]\n");
281 	exit(1);
282 }
283