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