Sync usage with man page.
[netbsd-mini2440.git] / sbin / dump / snapshot.c
blob224182bb528694389046dba51d38492a2811778f
1 /* $NetBSD: snapshot.c,v 1.3 2006/10/26 20:02:30 hannken Exp $ */
3 /*-
4 * Copyright (c) 2005 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Juergen Hannken-Illjes.
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.
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.
32 #include <sys/param.h>
33 #include <sys/ioctl.h>
34 #include <sys/mount.h>
35 #include <sys/stat.h>
37 #include <dev/fssvar.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
46 #include "snapshot.h"
49 * Create a snapshot of the file system currently mounted on the first argument
50 * using the second argument as backing store and return an open file
51 * descriptor for the snapshot. If the second argument is NULL, use the first
52 * as backing store. If the third argument is not NULL, it gets the time the
53 * snapshot was created. If the fourth argument is not NULL, it gets the
54 * snapshot device path.
56 int
57 snap_open(char *mountpoint, char *backup, time_t *snap_date, char **snap_dev)
59 int i, fd, israw, fsinternal, dounlink, flags;
60 char path[MAXPATHLEN], fss_dev[14];
61 dev_t mountdev;
62 struct fss_set fss;
63 struct fss_get fsg;
64 struct stat sb;
65 struct statvfs fsb;
67 dounlink = 0;
68 fd = -1;
70 fss.fss_mount = mountpoint;
71 fss.fss_bstore = backup ? backup : fss.fss_mount;
72 fss.fss_csize = 0;
74 if (stat(fss.fss_mount, &sb) < 0)
75 goto fail;
76 mountdev = sb.st_dev;
79 * Prepare the backing store. `backup' is either a raw device,
80 * a file or a directory. If it is a file, it must not exist.
82 israw = 0;
83 if (stat(fss.fss_bstore, &sb) == 0) {
84 if (S_ISDIR(sb.st_mode)) {
85 snprintf(path, sizeof(path),
86 "%s/XXXXXXXXXX", fss.fss_bstore);
87 fd = mkstemp(path);
88 fss.fss_bstore = path;
89 dounlink = 1;
90 } else if (S_ISCHR(sb.st_mode)) {
91 fd = open(fss.fss_bstore, O_RDWR);
92 israw = 1;
93 } else
94 goto fail;
95 } else {
96 fd = open(fss.fss_bstore, O_CREAT|O_EXCL|O_WRONLY, 0600);
97 dounlink = 1;
99 if (fd < 0)
100 goto fail;
102 if (fstat(fd, &sb) < 0)
103 goto fail;
104 fsinternal = (!israw && sb.st_dev == mountdev);
107 * If the backing store is a plain file and the snapshot
108 * is not file system internal, truncate to file system
109 * free space.
111 if (!israw && !fsinternal) {
112 if (statvfs(fss.fss_bstore, &fsb) < 0)
113 goto fail;
114 if (ftruncate(fd, (off_t)fsb.f_frsize*fsb.f_bavail) < 0)
115 goto fail;
118 if (close(fd) < 0)
119 goto fail;
122 * Create the snapshot on the first free snapshot device.
124 for (i = 0; ; i++) {
125 snprintf(fss_dev, sizeof(fss_dev), "/dev/rfss%d", i);
126 if ((fd = open(fss_dev, O_RDWR, 0)) < 0)
127 goto fail;
129 if (ioctl(fd, FSSIOFGET, &flags) < 0)
130 goto fail;
132 if (ioctl(fd, FSSIOCSET, &fss) < 0) {
133 if (errno != EBUSY)
134 goto fail;
135 close(fd);
136 fd = -1;
137 continue;
140 if (snap_dev != NULL) {
141 *snap_dev = strdup(fss_dev);
142 if (*snap_dev == NULL) {
143 ioctl(fd, FSSIOCCLR);
144 goto fail;
148 flags |= FSS_UNCONFIG_ON_CLOSE;
149 if (ioctl(fd, FSSIOCGET, &fsg) < 0 ||
150 ioctl(fd, FSSIOFSET, &flags) < 0 ||
151 (!israw && unlink(fss.fss_bstore) < 0)) {
152 ioctl(fd, FSSIOCCLR);
153 goto fail;
156 if (snap_date != NULL)
157 *snap_date = fsg.fsg_time.tv_sec;
158 return fd;
161 fail:
162 if (dounlink)
163 unlink(fss.fss_bstore);
164 if (fd >= 0)
165 close(fd);
167 return -1;