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