xref: /netbsd-src/usr.sbin/fssconfig/fssconfig.c (revision d1244e28087df1f325fff3254f3c979597c49d10)
1*d1244e28Shannken /*	$NetBSD: fssconfig.c,v 1.13 2017/12/21 15:52:19 hannken Exp $	*/
2fbae381aShannken 
3fbae381aShannken /*-
4fbae381aShannken  * Copyright (c) 2003 The NetBSD Foundation, Inc.
5fbae381aShannken  * All rights reserved.
6fbae381aShannken  *
7fbae381aShannken  * This code is derived from software contributed to The NetBSD Foundation
8fbae381aShannken  * by Juergen Hannken-Illjes.
9fbae381aShannken  *
10fbae381aShannken  * Redistribution and use in source and binary forms, with or without
11fbae381aShannken  * modification, are permitted provided that the following conditions
12fbae381aShannken  * are met:
13fbae381aShannken  * 1. Redistributions of source code must retain the above copyright
14fbae381aShannken  *    notice, this list of conditions and the following disclaimer.
15fbae381aShannken  * 2. Redistributions in binary form must reproduce the above copyright
16fbae381aShannken  *    notice, this list of conditions and the following disclaimer in the
17fbae381aShannken  *    documentation and/or other materials provided with the distribution.
18fbae381aShannken  *
19fbae381aShannken  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20fbae381aShannken  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21fbae381aShannken  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22fbae381aShannken  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23fbae381aShannken  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24fbae381aShannken  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25fbae381aShannken  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26fbae381aShannken  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27fbae381aShannken  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28fbae381aShannken  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29fbae381aShannken  * POSSIBILITY OF SUCH DAMAGE.
30fbae381aShannken  */
31fbae381aShannken 
32fbae381aShannken #include <sys/param.h>
33fbae381aShannken #include <sys/ioctl.h>
34fbae381aShannken #include <sys/mount.h>
35fbae381aShannken #include <sys/stat.h>
36fbae381aShannken 
37c6352516Schristos #include <stdio.h>
38fbae381aShannken #include <err.h>
39fbae381aShannken #include <errno.h>
40fbae381aShannken #include <fcntl.h>
41fbae381aShannken #include <stdlib.h>
42fbae381aShannken #include <string.h>
43fbae381aShannken #include <time.h>
44fbae381aShannken #include <unistd.h>
45fbae381aShannken #include <util.h>
46fbae381aShannken 
47fbae381aShannken #include <dev/fssvar.h>
48fbae381aShannken 
49d5966167Spgoyette #include "prog_ops.h"
50d5966167Spgoyette 
51d6ee580bSjoerg static int	vflag = 0;
52d6ee580bSjoerg static int	xflag = 0;
53fbae381aShannken 
54d6ee580bSjoerg static void	config(int, char **);
55d6ee580bSjoerg static void	unconfig(int, char **);
56d6ee580bSjoerg static void	list(int, char **);
57d6ee580bSjoerg __dead static void	usage(void);
58fbae381aShannken 
59fbae381aShannken int
main(int argc,char ** argv)60fbae381aShannken main(int argc, char **argv)
61fbae381aShannken {
62fbae381aShannken 	int ch;
63fbae381aShannken 	void (*action)(int, char **);
64fbae381aShannken 
658628665eSpgoyette 	action = NULL;
66fbae381aShannken 
67fbae381aShannken 	while ((ch = getopt(argc, argv, "cluvx")) != -1) {
68fbae381aShannken 		switch (ch) {
69fbae381aShannken 		case 'c':
708628665eSpgoyette 			if (action)
718628665eSpgoyette 				usage();
728628665eSpgoyette 			else
73fbae381aShannken 				action = config;
74fbae381aShannken 			break;
75fbae381aShannken 		case 'l':
768628665eSpgoyette 			if (action)
778628665eSpgoyette 				usage();
788628665eSpgoyette 			else
79fbae381aShannken 				action = list;
80fbae381aShannken 			break;
81fbae381aShannken 		case 'u':
828628665eSpgoyette 			if (action)
838628665eSpgoyette 				usage();
848628665eSpgoyette 			else
85fbae381aShannken 				action = unconfig;
86fbae381aShannken 			break;
87fbae381aShannken 		case 'v':
88fbae381aShannken 			vflag++;
89fbae381aShannken 			break;
90fbae381aShannken 		case 'x':
91fbae381aShannken 			xflag++;
92fbae381aShannken 			break;
93fbae381aShannken 		default:
94fbae381aShannken 		case '?':
95fbae381aShannken 			usage();
96fbae381aShannken 			/* NOTREACHED */
97fbae381aShannken 		}
98fbae381aShannken 	}
998628665eSpgoyette 	if (action == NULL)
1008628665eSpgoyette 		action = config;
101fbae381aShannken 
102fbae381aShannken 	argc -= optind;
103fbae381aShannken 	argv += optind;
104fbae381aShannken 
105fbae381aShannken 	(*action)(argc, argv);
106fbae381aShannken 
107fbae381aShannken 	exit(0);
108fbae381aShannken }
109fbae381aShannken 
110d6ee580bSjoerg static void
config(int argc,char ** argv)111fbae381aShannken config(int argc, char **argv)
112fbae381aShannken {
1138c21bc62Shannken 	int fd, isreg, istmp, ispersistent;
114fbae381aShannken 	char full[64], path[MAXPATHLEN];
115fbae381aShannken 	off_t bssize;
1168c21bc62Shannken 	dev_t mountdev;
117fbae381aShannken 	struct stat sbuf;
1186bd1d6d4Schristos 	struct statvfs fsbuf;
119fbae381aShannken 	struct fss_set fss;
120fbae381aShannken 
121fbae381aShannken 	if (argc < 3)
122fbae381aShannken 		usage();
123fbae381aShannken 
1248c21bc62Shannken 	istmp = ispersistent = 0;
125fbae381aShannken 
126fbae381aShannken 	fss.fss_mount = argv[1];
127fbae381aShannken 	fss.fss_bstore = argv[2];
1288c21bc62Shannken 
129d5966167Spgoyette 	if (prog_statvfs1(argv[1], &fsbuf, ST_WAIT) != 0 ||
130d5966167Spgoyette 	    prog_stat(argv[1], &sbuf) != 0)
1318c21bc62Shannken 		err(1, "stat %s", argv[1]);
1328c21bc62Shannken 	mountdev = sbuf.st_dev;
133*d1244e28Shannken 	if (stat(argv[2], &sbuf) == 0) {
134*d1244e28Shannken 		if (S_ISREG(sbuf.st_mode) && sbuf.st_dev == mountdev) {
1358c21bc62Shannken 			if ((sbuf.st_flags & SF_SNAPSHOT) == 0)
136*d1244e28Shannken 				errx(1, "%s: exists and is not a snapshot",
137*d1244e28Shannken 				    argv[2]);
1388c21bc62Shannken 			if (argc != 3)
1398c21bc62Shannken 				usage();
1408c21bc62Shannken 			isreg = ispersistent = 1;
1418c21bc62Shannken 
1428c21bc62Shannken 			goto configure;
143*d1244e28Shannken 		} else if (S_ISDIR(sbuf.st_mode)) {
144*d1244e28Shannken 			istmp = 1;
145*d1244e28Shannken 		}
1468c21bc62Shannken 	}
1478c21bc62Shannken 
1488c21bc62Shannken 	if (argc > 5)
1498c21bc62Shannken 		usage();
1508c21bc62Shannken 
151fbae381aShannken 	if (argc > 3)
152fbae381aShannken 		fss.fss_csize = strsuftoll("cluster size", argv[3], 0, INT_MAX);
153fbae381aShannken 	else
154fbae381aShannken 		fss.fss_csize = 0;
155fbae381aShannken 	if (argc > 4)
156fbae381aShannken 		bssize = strsuftoll("bs size", argv[4], 0, LLONG_MAX);
157fbae381aShannken 	else
1586bd1d6d4Schristos 		bssize = (off_t)fsbuf.f_blocks*fsbuf.f_frsize;
159fbae381aShannken 
160fbae381aShannken 	/*
161*d1244e28Shannken 	 * Create the backing store.
162fbae381aShannken 	 */
163*d1244e28Shannken 	if (istmp) {
164*d1244e28Shannken 		snprintf(path, sizeof(path), "%s/XXXXXXXXXX", argv[2]);
165fbae381aShannken 		fss.fss_bstore = path;
166*d1244e28Shannken 		fd = mkstemp(fss.fss_bstore);
167*d1244e28Shannken 	} else {
168*d1244e28Shannken 		fd = prog_open(fss.fss_bstore, O_CREAT|O_TRUNC|O_WRONLY, 0600);
169*d1244e28Shannken 	}
170*d1244e28Shannken 	if (fd < 0) {
171*d1244e28Shannken 		err(1, "create: %s", fss.fss_bstore);
172fbae381aShannken 	}
173d5966167Spgoyette 	if (prog_fstat(fd, &sbuf) < 0)
174fbae381aShannken 		err(1, "stat: %s", fss.fss_bstore);
1758c21bc62Shannken 	if (!ispersistent && sbuf.st_dev == mountdev)
1768c21bc62Shannken 		ispersistent = 1;
177fbae381aShannken 	isreg = S_ISREG(sbuf.st_mode);
1788c21bc62Shannken 	if (!ispersistent && isreg && ftruncate(fd, bssize) < 0)
179067a3b89Shannken 		err(1, "truncate %s", fss.fss_bstore);
180d5966167Spgoyette 	prog_close(fd);
181fbae381aShannken 
1828c21bc62Shannken configure:
183d5966167Spgoyette 	fd = opendisk1(argv[0], O_RDWR, full, sizeof(full), 0, prog_open);
184d5966167Spgoyette 	if (fd < 0) {
185fbae381aShannken 		if (istmp)
186fbae381aShannken 			unlink(fss.fss_bstore);
187fbae381aShannken 		err(1, "open: %s", argv[0]);
188fbae381aShannken 	}
189fbae381aShannken 
190a8055efcShannken 	fss.fss_flags = 0;
19105e91bfeShannken 	if ((xflag || istmp) && isreg)
19205e91bfeShannken 		fss.fss_flags |= FSS_UNLINK_ON_CREATE;
193a8055efcShannken 
194d5966167Spgoyette 	if (prog_ioctl(fd, FSSIOCSET, &fss) < 0) {
195fbae381aShannken 		if (istmp)
196fbae381aShannken 			unlink(fss.fss_bstore);
197fbae381aShannken 		err(1, "%s: FSSIOCSET", full);
198fbae381aShannken 	}
199fbae381aShannken 
200067a3b89Shannken 	if (vflag)
201067a3b89Shannken 		list(1, argv);
202fbae381aShannken }
203fbae381aShannken 
204d6ee580bSjoerg static void
unconfig(int argc,char ** argv)205fbae381aShannken unconfig(int argc, char **argv)
206fbae381aShannken {
207fbae381aShannken 	int fd;
208fbae381aShannken 	char full[64];
209fbae381aShannken 
2108628665eSpgoyette 	if (argc != 1 || xflag)
211fbae381aShannken 		usage();
212fbae381aShannken 
213067a3b89Shannken 	if (vflag)
214067a3b89Shannken 		list(1, argv);
215067a3b89Shannken 
216d5966167Spgoyette 	fd = opendisk1(argv[0], O_RDWR, full, sizeof(full), 0, prog_open);
217d5966167Spgoyette 	if (fd < 0)
218fbae381aShannken 		err(1, "open: %s", argv[0]);
219fbae381aShannken 
220d5966167Spgoyette 	if (prog_ioctl(fd, FSSIOCCLR) < 0)
221fbae381aShannken 		err(1, "%s: FSSIOCCLR", full);
222fbae381aShannken }
223fbae381aShannken 
224d6ee580bSjoerg static void
list(int argc,char ** argv)225fbae381aShannken list(int argc, char **argv)
226fbae381aShannken {
2276cb4c226Shannken 	int n, fd, flags;
228fbae381aShannken 	char *dev, path[64], full[64];
229fbae381aShannken 	char clbuf[5], bsbuf[5], tmbuf[64];
230fbae381aShannken 	time_t t;
231fbae381aShannken 	struct fss_get fsg;
232fbae381aShannken 
2338628665eSpgoyette 	if (argc > 1 || xflag)
234fbae381aShannken 		usage();
235fbae381aShannken 
236fbae381aShannken 	if (argc > 0)
237fbae381aShannken 		dev = argv[0];
238fbae381aShannken 	else
239fbae381aShannken 		dev = path;
240fbae381aShannken 
241fbae381aShannken 	for (n = 0; ; n++) {
242fbae381aShannken 		if (argc == 0)
243fbae381aShannken 			snprintf(path, sizeof(path), "fss%d", n);
244d5966167Spgoyette 		fd = opendisk1(dev, O_RDONLY, full, sizeof(full), 0, prog_open);
245d5966167Spgoyette 		if (fd < 0) {
246fbae381aShannken 			if (argc == 0 && (errno == ENOENT || errno == ENXIO))
247fbae381aShannken 				break;
248fbae381aShannken 			err(1, "open: %s", dev);
249fbae381aShannken 		}
250fbae381aShannken 
251d5966167Spgoyette 		if (prog_ioctl(fd, FSSIOFGET, &flags) < 0)
2526cb4c226Shannken 			flags = 0;
2536cb4c226Shannken 
254d5966167Spgoyette 		if (prog_ioctl(fd, FSSIOCGET, &fsg) < 0) {
255fbae381aShannken 			if (errno == ENXIO)
256fbae381aShannken 				printf("%s: not in use\n", dev);
257fbae381aShannken 			else
258fbae381aShannken 				err(1, "%s: FSSIOCGET", full);
259fbae381aShannken 		} else if (vflag) {
260fbae381aShannken 			humanize_number(clbuf, sizeof(clbuf),
261fbae381aShannken 			    (int64_t)fsg.fsg_csize,
262fbae381aShannken 			    "", HN_AUTOSCALE, HN_B|HN_NOSPACE);
263fbae381aShannken 
264fbae381aShannken 			humanize_number(bsbuf, sizeof(bsbuf),
265fbae381aShannken 			    (int64_t)fsg.fsg_bs_size*fsg.fsg_csize,
266fbae381aShannken 			    "", HN_AUTOSCALE, HN_B|HN_NOSPACE);
267fbae381aShannken 
268fbae381aShannken 			t = fsg.fsg_time.tv_sec;
269fbae381aShannken 			strftime(tmbuf, sizeof(tmbuf), "%F %T", localtime(&t));
270fbae381aShannken 
2716cb4c226Shannken 			printf("%s: %s, taken %s", dev, fsg.fsg_mount, tmbuf);
2726cb4c226Shannken 			if ((flags & FSS_UNCONFIG_ON_CLOSE) != 0)
2736cb4c226Shannken 				printf(", unconfig on close");
2748c21bc62Shannken 			if (fsg.fsg_csize == 0)
2756cb4c226Shannken 				printf(", file system internal\n");
2768c21bc62Shannken 			else
2776cb4c226Shannken 				printf(", %"PRId64" cluster of %s, %s backup\n",
2786cb4c226Shannken 				    fsg.fsg_mount_size, clbuf, bsbuf);
279fbae381aShannken 		} else
280fbae381aShannken 			printf("%s: %s\n", dev, fsg.fsg_mount);
281fbae381aShannken 
282d5966167Spgoyette 		prog_close(fd);
283fbae381aShannken 
284fbae381aShannken 		if (argc > 0)
285fbae381aShannken 			break;
286fbae381aShannken 	}
287fbae381aShannken }
288fbae381aShannken 
289d6ee580bSjoerg static void
usage(void)290fbae381aShannken usage(void)
291fbae381aShannken {
292fbae381aShannken 	fprintf(stderr, "%s",
2938c21bc62Shannken 	    "usage: fssconfig [-cxv] device path backup [cluster [size]]\n"
2948c21bc62Shannken 	    "       fssconfig -u [-v] device\n"
295fbae381aShannken 	    "       fssconfig -l [-v] [device]\n");
296fbae381aShannken 	exit(1);
297fbae381aShannken }
298