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