1 1.13 hannken /* $NetBSD: fssconfig.c,v 1.13 2017/12/21 15:52:19 hannken Exp $ */ 2 1.1 hannken 3 1.1 hannken /*- 4 1.1 hannken * Copyright (c) 2003 The NetBSD Foundation, Inc. 5 1.1 hannken * All rights reserved. 6 1.1 hannken * 7 1.1 hannken * This code is derived from software contributed to The NetBSD Foundation 8 1.1 hannken * by Juergen Hannken-Illjes. 9 1.1 hannken * 10 1.1 hannken * Redistribution and use in source and binary forms, with or without 11 1.1 hannken * modification, are permitted provided that the following conditions 12 1.1 hannken * are met: 13 1.1 hannken * 1. Redistributions of source code must retain the above copyright 14 1.1 hannken * notice, this list of conditions and the following disclaimer. 15 1.1 hannken * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 hannken * notice, this list of conditions and the following disclaimer in the 17 1.1 hannken * documentation and/or other materials provided with the distribution. 18 1.1 hannken * 19 1.1 hannken * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 hannken * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 hannken * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 hannken * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 hannken * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 hannken * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 hannken * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 hannken * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 hannken * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 hannken * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 hannken * POSSIBILITY OF SUCH DAMAGE. 30 1.1 hannken */ 31 1.1 hannken 32 1.1 hannken #include <sys/param.h> 33 1.1 hannken #include <sys/ioctl.h> 34 1.1 hannken #include <sys/mount.h> 35 1.1 hannken #include <sys/stat.h> 36 1.1 hannken 37 1.10 christos #include <stdio.h> 38 1.1 hannken #include <err.h> 39 1.1 hannken #include <errno.h> 40 1.1 hannken #include <fcntl.h> 41 1.1 hannken #include <stdlib.h> 42 1.1 hannken #include <string.h> 43 1.1 hannken #include <time.h> 44 1.1 hannken #include <unistd.h> 45 1.1 hannken #include <util.h> 46 1.1 hannken 47 1.1 hannken #include <dev/fssvar.h> 48 1.1 hannken 49 1.12 pgoyette #include "prog_ops.h" 50 1.12 pgoyette 51 1.8 joerg static int vflag = 0; 52 1.8 joerg static int xflag = 0; 53 1.1 hannken 54 1.8 joerg static void config(int, char **); 55 1.8 joerg static void unconfig(int, char **); 56 1.8 joerg static void list(int, char **); 57 1.8 joerg __dead static void usage(void); 58 1.1 hannken 59 1.1 hannken int 60 1.1 hannken main(int argc, char **argv) 61 1.1 hannken { 62 1.1 hannken int ch; 63 1.1 hannken void (*action)(int, char **); 64 1.1 hannken 65 1.11 pgoyette action = NULL; 66 1.1 hannken 67 1.1 hannken while ((ch = getopt(argc, argv, "cluvx")) != -1) { 68 1.1 hannken switch (ch) { 69 1.1 hannken case 'c': 70 1.11 pgoyette if (action) 71 1.11 pgoyette usage(); 72 1.11 pgoyette else 73 1.11 pgoyette action = config; 74 1.1 hannken break; 75 1.1 hannken case 'l': 76 1.11 pgoyette if (action) 77 1.11 pgoyette usage(); 78 1.11 pgoyette else 79 1.11 pgoyette action = list; 80 1.1 hannken break; 81 1.1 hannken case 'u': 82 1.11 pgoyette if (action) 83 1.11 pgoyette usage(); 84 1.11 pgoyette else 85 1.11 pgoyette action = unconfig; 86 1.1 hannken break; 87 1.1 hannken case 'v': 88 1.1 hannken vflag++; 89 1.1 hannken break; 90 1.1 hannken case 'x': 91 1.1 hannken xflag++; 92 1.1 hannken break; 93 1.1 hannken default: 94 1.1 hannken case '?': 95 1.1 hannken usage(); 96 1.1 hannken /* NOTREACHED */ 97 1.1 hannken } 98 1.1 hannken } 99 1.11 pgoyette if (action == NULL) 100 1.11 pgoyette action = config; 101 1.1 hannken 102 1.1 hannken argc -= optind; 103 1.1 hannken argv += optind; 104 1.1 hannken 105 1.1 hannken (*action)(argc, argv); 106 1.1 hannken 107 1.1 hannken exit(0); 108 1.1 hannken } 109 1.1 hannken 110 1.8 joerg static void 111 1.1 hannken config(int argc, char **argv) 112 1.1 hannken { 113 1.4 hannken int fd, isreg, istmp, ispersistent; 114 1.1 hannken char full[64], path[MAXPATHLEN]; 115 1.1 hannken off_t bssize; 116 1.4 hannken dev_t mountdev; 117 1.1 hannken struct stat sbuf; 118 1.3 christos struct statvfs fsbuf; 119 1.1 hannken struct fss_set fss; 120 1.1 hannken 121 1.1 hannken if (argc < 3) 122 1.1 hannken usage(); 123 1.1 hannken 124 1.4 hannken istmp = ispersistent = 0; 125 1.1 hannken 126 1.1 hannken fss.fss_mount = argv[1]; 127 1.1 hannken fss.fss_bstore = argv[2]; 128 1.4 hannken 129 1.12 pgoyette if (prog_statvfs1(argv[1], &fsbuf, ST_WAIT) != 0 || 130 1.12 pgoyette prog_stat(argv[1], &sbuf) != 0) 131 1.4 hannken err(1, "stat %s", argv[1]); 132 1.4 hannken mountdev = sbuf.st_dev; 133 1.13 hannken if (stat(argv[2], &sbuf) == 0) { 134 1.13 hannken if (S_ISREG(sbuf.st_mode) && sbuf.st_dev == mountdev) { 135 1.13 hannken if ((sbuf.st_flags & SF_SNAPSHOT) == 0) 136 1.13 hannken errx(1, "%s: exists and is not a snapshot", 137 1.13 hannken argv[2]); 138 1.13 hannken if (argc != 3) 139 1.13 hannken usage(); 140 1.13 hannken isreg = ispersistent = 1; 141 1.4 hannken 142 1.13 hannken goto configure; 143 1.13 hannken } else if (S_ISDIR(sbuf.st_mode)) { 144 1.13 hannken istmp = 1; 145 1.13 hannken } 146 1.4 hannken } 147 1.4 hannken 148 1.4 hannken if (argc > 5) 149 1.4 hannken usage(); 150 1.4 hannken 151 1.1 hannken if (argc > 3) 152 1.1 hannken fss.fss_csize = strsuftoll("cluster size", argv[3], 0, INT_MAX); 153 1.1 hannken else 154 1.1 hannken fss.fss_csize = 0; 155 1.1 hannken if (argc > 4) 156 1.1 hannken bssize = strsuftoll("bs size", argv[4], 0, LLONG_MAX); 157 1.1 hannken else 158 1.3 christos bssize = (off_t)fsbuf.f_blocks*fsbuf.f_frsize; 159 1.1 hannken 160 1.1 hannken /* 161 1.13 hannken * Create the backing store. 162 1.1 hannken */ 163 1.13 hannken if (istmp) { 164 1.13 hannken snprintf(path, sizeof(path), "%s/XXXXXXXXXX", argv[2]); 165 1.13 hannken fss.fss_bstore = path; 166 1.13 hannken fd = mkstemp(fss.fss_bstore); 167 1.13 hannken } else { 168 1.13 hannken fd = prog_open(fss.fss_bstore, O_CREAT|O_TRUNC|O_WRONLY, 0600); 169 1.13 hannken } 170 1.12 pgoyette if (fd < 0) { 171 1.13 hannken err(1, "create: %s", fss.fss_bstore); 172 1.1 hannken } 173 1.12 pgoyette if (prog_fstat(fd, &sbuf) < 0) 174 1.1 hannken err(1, "stat: %s", fss.fss_bstore); 175 1.4 hannken if (!ispersistent && sbuf.st_dev == mountdev) 176 1.4 hannken ispersistent = 1; 177 1.1 hannken isreg = S_ISREG(sbuf.st_mode); 178 1.4 hannken if (!ispersistent && isreg && ftruncate(fd, bssize) < 0) 179 1.2 hannken err(1, "truncate %s", fss.fss_bstore); 180 1.12 pgoyette prog_close(fd); 181 1.1 hannken 182 1.4 hannken configure: 183 1.12 pgoyette fd = opendisk1(argv[0], O_RDWR, full, sizeof(full), 0, prog_open); 184 1.12 pgoyette if (fd < 0) { 185 1.1 hannken if (istmp) 186 1.1 hannken unlink(fss.fss_bstore); 187 1.1 hannken err(1, "open: %s", argv[0]); 188 1.1 hannken } 189 1.1 hannken 190 1.9 hannken fss.fss_flags = 0; 191 1.7 hannken if ((xflag || istmp) && isreg) 192 1.7 hannken fss.fss_flags |= FSS_UNLINK_ON_CREATE; 193 1.9 hannken 194 1.12 pgoyette if (prog_ioctl(fd, FSSIOCSET, &fss) < 0) { 195 1.1 hannken if (istmp) 196 1.1 hannken unlink(fss.fss_bstore); 197 1.1 hannken err(1, "%s: FSSIOCSET", full); 198 1.1 hannken } 199 1.1 hannken 200 1.2 hannken if (vflag) 201 1.2 hannken list(1, argv); 202 1.1 hannken } 203 1.1 hannken 204 1.8 joerg static void 205 1.1 hannken unconfig(int argc, char **argv) 206 1.1 hannken { 207 1.1 hannken int fd; 208 1.1 hannken char full[64]; 209 1.1 hannken 210 1.11 pgoyette if (argc != 1 || xflag) 211 1.1 hannken usage(); 212 1.1 hannken 213 1.2 hannken if (vflag) 214 1.2 hannken list(1, argv); 215 1.2 hannken 216 1.12 pgoyette fd = opendisk1(argv[0], O_RDWR, full, sizeof(full), 0, prog_open); 217 1.12 pgoyette if (fd < 0) 218 1.1 hannken err(1, "open: %s", argv[0]); 219 1.1 hannken 220 1.12 pgoyette if (prog_ioctl(fd, FSSIOCCLR) < 0) 221 1.1 hannken err(1, "%s: FSSIOCCLR", full); 222 1.1 hannken } 223 1.1 hannken 224 1.8 joerg static void 225 1.1 hannken list(int argc, char **argv) 226 1.1 hannken { 227 1.5 hannken int n, fd, flags; 228 1.1 hannken char *dev, path[64], full[64]; 229 1.1 hannken char clbuf[5], bsbuf[5], tmbuf[64]; 230 1.1 hannken time_t t; 231 1.1 hannken struct fss_get fsg; 232 1.1 hannken 233 1.11 pgoyette if (argc > 1 || xflag) 234 1.1 hannken usage(); 235 1.1 hannken 236 1.1 hannken if (argc > 0) 237 1.1 hannken dev = argv[0]; 238 1.1 hannken else 239 1.1 hannken dev = path; 240 1.1 hannken 241 1.1 hannken for (n = 0; ; n++) { 242 1.1 hannken if (argc == 0) 243 1.1 hannken snprintf(path, sizeof(path), "fss%d", n); 244 1.12 pgoyette fd = opendisk1(dev, O_RDONLY, full, sizeof(full), 0, prog_open); 245 1.12 pgoyette if (fd < 0) { 246 1.1 hannken if (argc == 0 && (errno == ENOENT || errno == ENXIO)) 247 1.1 hannken break; 248 1.1 hannken err(1, "open: %s", dev); 249 1.1 hannken } 250 1.1 hannken 251 1.12 pgoyette if (prog_ioctl(fd, FSSIOFGET, &flags) < 0) 252 1.5 hannken flags = 0; 253 1.5 hannken 254 1.12 pgoyette if (prog_ioctl(fd, FSSIOCGET, &fsg) < 0) { 255 1.1 hannken if (errno == ENXIO) 256 1.1 hannken printf("%s: not in use\n", dev); 257 1.1 hannken else 258 1.1 hannken err(1, "%s: FSSIOCGET", full); 259 1.1 hannken } else if (vflag) { 260 1.1 hannken humanize_number(clbuf, sizeof(clbuf), 261 1.1 hannken (int64_t)fsg.fsg_csize, 262 1.1 hannken "", HN_AUTOSCALE, HN_B|HN_NOSPACE); 263 1.1 hannken 264 1.1 hannken humanize_number(bsbuf, sizeof(bsbuf), 265 1.1 hannken (int64_t)fsg.fsg_bs_size*fsg.fsg_csize, 266 1.1 hannken "", HN_AUTOSCALE, HN_B|HN_NOSPACE); 267 1.1 hannken 268 1.1 hannken t = fsg.fsg_time.tv_sec; 269 1.1 hannken strftime(tmbuf, sizeof(tmbuf), "%F %T", localtime(&t)); 270 1.1 hannken 271 1.5 hannken printf("%s: %s, taken %s", dev, fsg.fsg_mount, tmbuf); 272 1.5 hannken if ((flags & FSS_UNCONFIG_ON_CLOSE) != 0) 273 1.5 hannken printf(", unconfig on close"); 274 1.5 hannken if (fsg.fsg_csize == 0) 275 1.5 hannken printf(", file system internal\n"); 276 1.4 hannken else 277 1.5 hannken printf(", %"PRId64" cluster of %s, %s backup\n", 278 1.5 hannken fsg.fsg_mount_size, clbuf, bsbuf); 279 1.1 hannken } else 280 1.1 hannken printf("%s: %s\n", dev, fsg.fsg_mount); 281 1.1 hannken 282 1.12 pgoyette prog_close(fd); 283 1.1 hannken 284 1.1 hannken if (argc > 0) 285 1.1 hannken break; 286 1.1 hannken } 287 1.1 hannken } 288 1.1 hannken 289 1.8 joerg static void 290 1.1 hannken usage(void) 291 1.1 hannken { 292 1.1 hannken fprintf(stderr, "%s", 293 1.4 hannken "usage: fssconfig [-cxv] device path backup [cluster [size]]\n" 294 1.4 hannken " fssconfig -u [-v] device\n" 295 1.1 hannken " fssconfig -l [-v] [device]\n"); 296 1.1 hannken exit(1); 297 1.1 hannken } 298