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