1/* $NetBSD$ */ 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 <err.h> 38#include <errno.h> 39#include <fcntl.h> 40#include <stdlib.h> 41#include <string.h> 42#include <time.h> 43#include <unistd.h> 44#include <util.h> 45 46#include <dev/fssvar.h> 47 48static int vflag = 0; 49static int xflag = 0; 50 51static void config(int, char **); 52static void unconfig(int, char **); 53static void list(int, char **); 54__dead static void usage(void); 55 56int 57main(int argc, char **argv) 58{ 59 int ch; 60 void (*action)(int, char **); 61 62 action = config; 63 64 while ((ch = getopt(argc, argv, "cluvx")) != -1) { 65 switch (ch) { 66 case 'c': 67 action = config; 68 break; 69 case 'l': 70 action = list; 71 break; 72 case 'u': 73 action = unconfig; 74 break; 75 case 'v': 76 vflag++; 77 break; 78 case 'x': 79 xflag++; 80 break; 81 default: 82 case '?': 83 usage(); 84 /* NOTREACHED */ 85 } 86 } 87 88 argc -= optind; 89 argv += optind; 90 91 (*action)(argc, argv); 92 93 exit(0); 94} 95 96static void 97config(int argc, char **argv) 98{ 99 int fd, isreg, istmp, ispersistent; 100 char full[64], path[MAXPATHLEN]; 101 off_t bssize; 102 dev_t mountdev; 103 struct stat sbuf; 104 struct statvfs fsbuf; 105 struct fss_set fss; 106 107 if (argc < 3) 108 usage(); 109 110 istmp = ispersistent = 0; 111 112 fss.fss_mount = argv[1]; 113 fss.fss_bstore = argv[2]; 114 115 if (statvfs(argv[1], &fsbuf) != 0 || stat(argv[1], &sbuf) != 0) 116 err(1, "stat %s", argv[1]); 117 mountdev = sbuf.st_dev; 118 if (stat(argv[2], &sbuf) == 0 && 119 S_ISREG(sbuf.st_mode) && 120 sbuf.st_dev == mountdev) { 121 if ((sbuf.st_flags & SF_SNAPSHOT) == 0) 122 errx(1, "%s: exists and is not a snapshot", argv[2]); 123 if (argc != 3) 124 usage(); 125 isreg = ispersistent = 1; 126 127 goto configure; 128 } 129 130 if (argc > 5) 131 usage(); 132 133 if (argc > 3) 134 fss.fss_csize = strsuftoll("cluster size", argv[3], 0, INT_MAX); 135 else 136 fss.fss_csize = 0; 137 if (argc > 4) 138 bssize = strsuftoll("bs size", argv[4], 0, LLONG_MAX); 139 else 140 bssize = (off_t)fsbuf.f_blocks*fsbuf.f_frsize; 141 142 /* 143 * Create the backing store. If it is a directory, create a temporary 144 * file and set the unlink flag. 145 */ 146 if ((fd = open(fss.fss_bstore, O_CREAT|O_TRUNC|O_WRONLY, 0600)) < 0) { 147 if (errno != EISDIR) 148 err(1, "create: %s", fss.fss_bstore); 149 snprintf(path, sizeof(path), "%s/XXXXXXXXXX", fss.fss_bstore); 150 if ((fd = mkstemp(path)) < 0) 151 err(1, "mkstemp: %s", path); 152 fss.fss_bstore = path; 153 istmp = 1; 154 } 155 if (fstat(fd, &sbuf) < 0) 156 err(1, "stat: %s", fss.fss_bstore); 157 if (!ispersistent && sbuf.st_dev == mountdev) 158 ispersistent = 1; 159 isreg = S_ISREG(sbuf.st_mode); 160 if (!ispersistent && isreg && ftruncate(fd, bssize) < 0) 161 err(1, "truncate %s", fss.fss_bstore); 162 close(fd); 163 164configure: 165 if ((fd = opendisk(argv[0], O_RDWR, full, sizeof(full), 0)) < 0) { 166 if (istmp) 167 unlink(fss.fss_bstore); 168 err(1, "open: %s", argv[0]); 169 } 170 171 fss.fss_flags = 0; 172 if ((xflag || istmp) && isreg) 173 fss.fss_flags |= FSS_UNLINK_ON_CREATE; 174 175 if (ioctl(fd, FSSIOCSET, &fss) < 0) { 176 if (istmp) 177 unlink(fss.fss_bstore); 178 err(1, "%s: FSSIOCSET", full); 179 } 180 181 if (vflag) 182 list(1, argv); 183} 184 185static void 186unconfig(int argc, char **argv) 187{ 188 int fd; 189 char full[64]; 190 191 if (argc != 1) 192 usage(); 193 194 if (vflag) 195 list(1, argv); 196 197 if ((fd = opendisk(argv[0], O_RDWR, full, sizeof(full), 0)) < 0) 198 err(1, "open: %s", argv[0]); 199 200 if (ioctl(fd, FSSIOCCLR) < 0) 201 err(1, "%s: FSSIOCCLR", full); 202} 203 204static void 205list(int argc, char **argv) 206{ 207 int n, fd, flags; 208 char *dev, path[64], full[64]; 209 char clbuf[5], bsbuf[5], tmbuf[64]; 210 time_t t; 211 struct fss_get fsg; 212 213 if (argc > 1) 214 usage(); 215 216 if (argc > 0) 217 dev = argv[0]; 218 else 219 dev = path; 220 221 for (n = 0; ; n++) { 222 if (argc == 0) 223 snprintf(path, sizeof(path), "fss%d", n); 224 if ((fd = opendisk(dev, O_RDONLY, full, sizeof(full), 0)) < 0) { 225 if (argc == 0 && (errno == ENOENT || errno == ENXIO)) 226 break; 227 err(1, "open: %s", dev); 228 } 229 230 if (ioctl(fd, FSSIOFGET, &flags) < 0) 231 flags = 0; 232 233 if (ioctl(fd, FSSIOCGET, &fsg) < 0) { 234 if (errno == ENXIO) 235 printf("%s: not in use\n", dev); 236 else 237 err(1, "%s: FSSIOCGET", full); 238 } else if (vflag) { 239 humanize_number(clbuf, sizeof(clbuf), 240 (int64_t)fsg.fsg_csize, 241 "", HN_AUTOSCALE, HN_B|HN_NOSPACE); 242 243 humanize_number(bsbuf, sizeof(bsbuf), 244 (int64_t)fsg.fsg_bs_size*fsg.fsg_csize, 245 "", HN_AUTOSCALE, HN_B|HN_NOSPACE); 246 247 t = fsg.fsg_time.tv_sec; 248 strftime(tmbuf, sizeof(tmbuf), "%F %T", localtime(&t)); 249 250 printf("%s: %s, taken %s", dev, fsg.fsg_mount, tmbuf); 251 if ((flags & FSS_UNCONFIG_ON_CLOSE) != 0) 252 printf(", unconfig on close"); 253 if (fsg.fsg_csize == 0) 254 printf(", file system internal\n"); 255 else 256 printf(", %"PRId64" cluster of %s, %s backup\n", 257 fsg.fsg_mount_size, clbuf, bsbuf); 258 } else 259 printf("%s: %s\n", dev, fsg.fsg_mount); 260 261 close(fd); 262 263 if (argc > 0) 264 break; 265 } 266} 267 268static void 269usage(void) 270{ 271 fprintf(stderr, "%s", 272 "usage: fssconfig [-cxv] device path backup [cluster [size]]\n" 273 " fssconfig -u [-v] device\n" 274 " fssconfig -l [-v] [device]\n"); 275 exit(1); 276} 277