1 /* $NetBSD: snapshot.c,v 1.2 2005/04/19 08:10:43 hannken Exp $ */ 2 3 /*- 4 * Copyright (c) 2005 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 <dev/fssvar.h> 45 46 #include <errno.h> 47 #include <fcntl.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <unistd.h> 51 52 #include "snapshot.h" 53 54 /* 55 * Create a snapshot of the file system currently mounted on the first argument 56 * using the second argument as backing store and return an open file 57 * descriptor for the snapshot. If the second argument is NULL, use the first 58 * as backing store. If the third argument is not NULL, it gets the time the 59 * snapshot was created. 60 */ 61 int 62 snap_open(char *mountpoint, char *backup, time_t *snap_date) 63 { 64 int i, fd, israw, fsinternal, dounlink, flags; 65 char path[MAXPATHLEN], fss_dev[14]; 66 dev_t mountdev; 67 struct fss_set fss; 68 struct fss_get fsg; 69 struct stat sb; 70 struct statvfs fsb; 71 72 dounlink = 0; 73 fd = -1; 74 75 fss.fss_mount = mountpoint; 76 fss.fss_bstore = backup ? backup : fss.fss_mount; 77 fss.fss_csize = 0; 78 79 if (stat(fss.fss_mount, &sb) < 0) 80 goto fail; 81 mountdev = sb.st_dev; 82 83 /* 84 * Prepare the backing store. `backup' is either a raw device, 85 * a file or a directory. If it is a file, it must not exist. 86 */ 87 israw = 0; 88 if (stat(fss.fss_bstore, &sb) == 0) { 89 if (S_ISDIR(sb.st_mode)) { 90 snprintf(path, sizeof(path), 91 "%s/XXXXXXXXXX", fss.fss_bstore); 92 fd = mkstemp(path); 93 fss.fss_bstore = path; 94 dounlink = 1; 95 } else if (S_ISCHR(sb.st_mode)) { 96 fd = open(fss.fss_bstore, O_RDWR); 97 israw = 1; 98 } else 99 goto fail; 100 } else { 101 fd = open(fss.fss_bstore, O_CREAT|O_EXCL|O_WRONLY, 0600); 102 dounlink = 1; 103 } 104 if (fd < 0) 105 goto fail; 106 107 if (fstat(fd, &sb) < 0) 108 goto fail; 109 fsinternal = (!israw && sb.st_dev == mountdev); 110 111 /* 112 * If the backing store is a plain file and the snapshot 113 * is not file system internal, truncate to file system 114 * free space. 115 */ 116 if (!israw && !fsinternal) { 117 if (statvfs(fss.fss_bstore, &fsb) < 0) 118 goto fail; 119 if (ftruncate(fd, (off_t)fsb.f_frsize*fsb.f_bavail) < 0) 120 goto fail; 121 } 122 123 if (close(fd) < 0) 124 goto fail; 125 126 /* 127 * Create the snapshot on the first free snapshot device. 128 */ 129 for (i = 0; ; i++) { 130 snprintf(fss_dev, sizeof(fss_dev), "/dev/rfss%d", i); 131 if ((fd = open(fss_dev, O_RDWR, 0)) < 0) 132 goto fail; 133 134 if (ioctl(fd, FSSIOFGET, &flags) < 0) 135 goto fail; 136 137 if (ioctl(fd, FSSIOCSET, &fss) < 0) { 138 if (errno != EBUSY) 139 goto fail; 140 close(fd); 141 fd = -1; 142 continue; 143 } 144 145 flags |= FSS_UNCONFIG_ON_CLOSE; 146 if (ioctl(fd, FSSIOCGET, &fsg) < 0 || 147 ioctl(fd, FSSIOFSET, &flags) < 0 || 148 (!israw && unlink(fss.fss_bstore) < 0)) { 149 ioctl(fd, FSSIOCCLR); 150 goto fail; 151 } 152 153 if (snap_date != NULL) 154 *snap_date = fsg.fsg_time.tv_sec; 155 return fd; 156 } 157 158 fail: 159 if (dounlink) 160 unlink(fss.fss_bstore); 161 if (fd >= 0) 162 close(fd); 163 164 return -1; 165 } 166