fssconfig.c revision 1.4 1 /* $NetBSD: fssconfig.c,v 1.4 2004/05/25 14:55:47 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;
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, FSSIOCGET, &fsg) < 0) {
237 if (errno == ENXIO)
238 printf("%s: not in use\n", dev);
239 else
240 err(1, "%s: FSSIOCGET", full);
241 } else if (vflag) {
242 humanize_number(clbuf, sizeof(clbuf),
243 (int64_t)fsg.fsg_csize,
244 "", HN_AUTOSCALE, HN_B|HN_NOSPACE);
245
246 humanize_number(bsbuf, sizeof(bsbuf),
247 (int64_t)fsg.fsg_bs_size*fsg.fsg_csize,
248 "", HN_AUTOSCALE, HN_B|HN_NOSPACE);
249
250 t = fsg.fsg_time.tv_sec;
251 strftime(tmbuf, sizeof(tmbuf), "%F %T", localtime(&t));
252
253 if (fsg.fsg_csize == 0)
254 printf("%s: %s, persistent, taken %s\n", dev,
255 fsg.fsg_mount, tmbuf);
256 else
257 printf("%s: %s, taken %s, %" PRId64 " clusters"
258 " of %s, %s backup\n", dev, fsg.fsg_mount,
259 tmbuf, fsg.fsg_mount_size, clbuf, bsbuf);
260 } else
261 printf("%s: %s\n", dev, fsg.fsg_mount);
262
263 close(fd);
264
265 if (argc > 0)
266 break;
267 }
268 }
269
270 void
271 usage(void)
272 {
273 fprintf(stderr, "%s",
274 "usage: fssconfig [-cxv] device path backup [cluster [size]]\n"
275 " fssconfig -u [-v] device\n"
276 " fssconfig -l [-v] [device]\n");
277 exit(1);
278 }
279