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