Home | History | Annotate | Line # | Download | only in fssconfig
fssconfig.c revision 1.4
      1 /*	$NetBSD: fssconfig.c,v 1.4 2004/05/25 14:55:47 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;
    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, FSSIOCGET, &fsg) < 0) {
    237 			if (errno == ENXIO)
    238 				printf("%s: not in use\n", dev);
    239 			else
    240 				err(1, "%s: FSSIOCGET", full);
    241 		} else if (vflag) {
    242 			humanize_number(clbuf, sizeof(clbuf),
    243 			    (int64_t)fsg.fsg_csize,
    244 			    "", HN_AUTOSCALE, HN_B|HN_NOSPACE);
    245 
    246 			humanize_number(bsbuf, sizeof(bsbuf),
    247 			    (int64_t)fsg.fsg_bs_size*fsg.fsg_csize,
    248 			    "", HN_AUTOSCALE, HN_B|HN_NOSPACE);
    249 
    250 			t = fsg.fsg_time.tv_sec;
    251 			strftime(tmbuf, sizeof(tmbuf), "%F %T", localtime(&t));
    252 
    253 			if (fsg.fsg_csize == 0)
    254 				printf("%s: %s, persistent, taken %s\n", dev,
    255 				    fsg.fsg_mount, tmbuf);
    256 			else
    257 				printf("%s: %s, taken %s, %" PRId64 " clusters"
    258 				    " of %s, %s backup\n", dev, fsg.fsg_mount,
    259 				    tmbuf, fsg.fsg_mount_size, clbuf, bsbuf);
    260 		} else
    261 			printf("%s: %s\n", dev, fsg.fsg_mount);
    262 
    263 		close(fd);
    264 
    265 		if (argc > 0)
    266 			break;
    267 	}
    268 }
    269 
    270 void
    271 usage(void)
    272 {
    273 	fprintf(stderr, "%s",
    274 	    "usage: fssconfig [-cxv] device path backup [cluster [size]]\n"
    275 	    "       fssconfig -u [-v] device\n"
    276 	    "       fssconfig -l [-v] [device]\n");
    277 	exit(1);
    278 }
    279