xref: /dragonfly/sbin/hammer/cmd_snapshot.c (revision 3267eb8a)
16b669ab4SMichael Neumann /*
26b669ab4SMichael Neumann  * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
36b669ab4SMichael Neumann  *
46b669ab4SMichael Neumann  * This code is derived from software contributed to The DragonFly Project
56b669ab4SMichael Neumann  * by Matthew Dillon <dillon@backplane.com>
66b669ab4SMichael Neumann  *
76b669ab4SMichael Neumann  * Redistribution and use in source and binary forms, with or without
86b669ab4SMichael Neumann  * modification, are permitted provided that the following conditions
96b669ab4SMichael Neumann  * are met:
106b669ab4SMichael Neumann  *
116b669ab4SMichael Neumann  * 1. Redistributions of source code must retain the above copyright
126b669ab4SMichael Neumann  *    notice, this list of conditions and the following disclaimer.
136b669ab4SMichael Neumann  * 2. Redistributions in binary form must reproduce the above copyright
146b669ab4SMichael Neumann  *    notice, this list of conditions and the following disclaimer in
156b669ab4SMichael Neumann  *    the documentation and/or other materials provided with the
166b669ab4SMichael Neumann  *    distribution.
176b669ab4SMichael Neumann  * 3. Neither the name of The DragonFly Project nor the names of its
186b669ab4SMichael Neumann  *    contributors may be used to endorse or promote products derived
196b669ab4SMichael Neumann  *    from this software without specific, prior written permission.
206b669ab4SMichael Neumann  *
216b669ab4SMichael Neumann  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
226b669ab4SMichael Neumann  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
236b669ab4SMichael Neumann  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
246b669ab4SMichael Neumann  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
256b669ab4SMichael Neumann  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
266b669ab4SMichael Neumann  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
276b669ab4SMichael Neumann  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
286b669ab4SMichael Neumann  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
296b669ab4SMichael Neumann  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
306b669ab4SMichael Neumann  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
316b669ab4SMichael Neumann  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
326b669ab4SMichael Neumann  * SUCH DAMAGE.
336b669ab4SMichael Neumann  *
34*3267eb8aSSascha Wildner  * $DragonFly: src/sbin/hammer/cmd_snapshot.c,v 1.6 2008/06/28 14:18:00 swildner Exp $
356b669ab4SMichael Neumann  */
366b669ab4SMichael Neumann 
376b669ab4SMichael Neumann #include "hammer.h"
386b669ab4SMichael Neumann #include <sys/param.h>
396b669ab4SMichael Neumann #include <sys/mount.h>
4096e6b862SMichael Neumann #include <sys/types.h>
4196e6b862SMichael Neumann #include <sys/stat.h>
426b669ab4SMichael Neumann #include <unistd.h>
43f8052532SMichael Neumann #include <string.h>
44f8052532SMichael Neumann #include <time.h>
456b669ab4SMichael Neumann 
4696e6b862SMichael Neumann #define DEFAULT_SNAPSHOT_NAME "snap-%Y%m%d-%H%M"
4796e6b862SMichael Neumann 
486b669ab4SMichael Neumann static void snapshot_usage(int exit_code);
496b669ab4SMichael Neumann 
506b669ab4SMichael Neumann /*
51f8052532SMichael Neumann  * snapshot <softlink-dir-in-filesystem>
52f8052532SMichael Neumann  * snapshot <filesystem> <softlink-dir>
536b669ab4SMichael Neumann  */
546b669ab4SMichael Neumann void
556b669ab4SMichael Neumann hammer_cmd_snapshot(char **av, int ac)
566b669ab4SMichael Neumann {
576b669ab4SMichael Neumann 	const char *filesystem;
5896e6b862SMichael Neumann 	const char *softlink_dir;
5996e6b862SMichael Neumann 	char *softlink_fmt;
606b669ab4SMichael Neumann 	struct statfs buf;
6196e6b862SMichael Neumann 	struct stat st;
626b669ab4SMichael Neumann 	struct hammer_ioc_synctid synctid;
636b669ab4SMichael Neumann 	char *from;
646b669ab4SMichael Neumann 	char *to;
656b669ab4SMichael Neumann 
66f8052532SMichael Neumann 	if (ac == 1) {
67f8052532SMichael Neumann 		filesystem = NULL;
6896e6b862SMichael Neumann 		softlink_dir = av[0];
69*3267eb8aSSascha Wildner 	} else if (ac == 2) {
70f8052532SMichael Neumann 		filesystem = av[0];
7196e6b862SMichael Neumann 		softlink_dir = av[1];
72*3267eb8aSSascha Wildner 	} else {
736b669ab4SMichael Neumann 		snapshot_usage(1);
74f8052532SMichael Neumann 	}
756b669ab4SMichael Neumann 
7696e6b862SMichael Neumann 	if (stat(softlink_dir, &st) == 0) {
7796e6b862SMichael Neumann 		if (!S_ISDIR(st.st_mode))
7896e6b862SMichael Neumann 			err(2, "File %s already exists", softlink_dir);
796b669ab4SMichael Neumann 
8096e6b862SMichael Neumann 		if (filesystem == NULL) {
81f8052532SMichael Neumann 			if (statfs(softlink_dir, &buf) != 0) {
82f8052532SMichael Neumann 				err(2, "Unable to determine filesystem of %s",
83f8052532SMichael Neumann 				    softlink_dir);
84f8052532SMichael Neumann 			}
856b669ab4SMichael Neumann 			filesystem = buf.f_mntonname;
8696e6b862SMichael Neumann 		}
8796e6b862SMichael Neumann 
8896e6b862SMichael Neumann 		softlink_fmt = malloc(strlen(softlink_dir) + 1 + 1 +
8996e6b862SMichael Neumann 		                      sizeof(DEFAULT_SNAPSHOT_NAME));
9096e6b862SMichael Neumann 		if (softlink_fmt == NULL)
9196e6b862SMichael Neumann 			err(2, "Failed to allocate string");
9296e6b862SMichael Neumann 
9396e6b862SMichael Neumann 		strcpy(softlink_fmt, softlink_dir);
9496e6b862SMichael Neumann 		if (softlink_fmt[strlen(softlink_fmt)-1] != '/')
9596e6b862SMichael Neumann 			strcat(softlink_fmt, "/");
9696e6b862SMichael Neumann 		strcat(softlink_fmt, DEFAULT_SNAPSHOT_NAME);
97*3267eb8aSSascha Wildner 	} else {
9896e6b862SMichael Neumann 		softlink_fmt = strdup(softlink_dir);
9996e6b862SMichael Neumann 
10096e6b862SMichael Neumann 		if (filesystem == NULL) {
10196e6b862SMichael Neumann 			/*
10296e6b862SMichael Neumann 			 * strip-off last '/path' segment to get the softlink
10396e6b862SMichael Neumann 			 * directory, which we need to determine the filesystem
10496e6b862SMichael Neumann 			 * we are on.
10596e6b862SMichael Neumann 			 */
10696e6b862SMichael Neumann 			char *pos = strrchr(softlink_fmt, '/');
10796e6b862SMichael Neumann 			if (pos != NULL)
10896e6b862SMichael Neumann 				*pos = '\0';
10996e6b862SMichael Neumann 
11096e6b862SMichael Neumann 			if (stat(softlink_fmt, &st) != 0 ||
11196e6b862SMichael Neumann 			    !S_ISDIR(st.st_mode)) {
11296e6b862SMichael Neumann 				err(2, "Unable to determine softlink dir %s",
11396e6b862SMichael Neumann 				    softlink_fmt);
11496e6b862SMichael Neumann 			}
11596e6b862SMichael Neumann 			if (statfs(softlink_fmt, &buf) != 0) {
11696e6b862SMichael Neumann 				err(2, "Unable to determine filesystem of %s",
11796e6b862SMichael Neumann 				    softlink_fmt);
11896e6b862SMichael Neumann 			}
11996e6b862SMichael Neumann 			filesystem = buf.f_mntonname;
12096e6b862SMichael Neumann 
12196e6b862SMichael Neumann 			if (pos != NULL)
12296e6b862SMichael Neumann 				*pos = '/';
12396e6b862SMichael Neumann 		}
124a231693eSMichael Neumann 	}
125f8052532SMichael Neumann 
126f8052532SMichael Neumann 	/*
127f8052532SMichael Neumann 	 * Synctid
128f8052532SMichael Neumann 	 */
1296b669ab4SMichael Neumann 	bzero(&synctid, sizeof(synctid));
1306b669ab4SMichael Neumann 	synctid.op = HAMMER_SYNCTID_SYNC2;
13196e6b862SMichael Neumann 	int fd = open(filesystem, O_RDONLY);
1326b669ab4SMichael Neumann 	if (fd < 0)
1336b669ab4SMichael Neumann 		err(2, "Unable to open %s", filesystem);
1346764f177SMichael Neumann 	if (ioctl(fd, HAMMERIOC_SYNCTID, &synctid) < 0)
1356b669ab4SMichael Neumann 		err(2, "Synctid %s failed", filesystem);
136f8052532SMichael Neumann 	close(fd);
1376764f177SMichael Neumann 
1386b669ab4SMichael Neumann 	asprintf(&from, "%s@@0x%016llx", filesystem, synctid.tid);
1396b669ab4SMichael Neumann 	if (from == NULL)
1406b669ab4SMichael Neumann 		err(2, "Couldn't generate string");
1416b669ab4SMichael Neumann 
142f8052532SMichael Neumann 	int sz = strlen(softlink_fmt) + 50;
143f8052532SMichael Neumann 	to = malloc(sz);
1446b669ab4SMichael Neumann 	if (to == NULL)
145f8052532SMichael Neumann 		err(2, "Failed to allocate string");
146f8052532SMichael Neumann 
147f8052532SMichael Neumann 	time_t t = time(NULL);
148f8052532SMichael Neumann 	if (strftime(to, sz, softlink_fmt, localtime(&t)) == 0)
149f8052532SMichael Neumann 		err(2, "String buffer too small");
1506b669ab4SMichael Neumann 
1516b669ab4SMichael Neumann 	if (symlink(from, to) != 0)
1526b669ab4SMichael Neumann 		err(2, "Unable to symlink %s to %s", from, to);
1536b669ab4SMichael Neumann 
1546b669ab4SMichael Neumann 	printf("%s\n", to);
1556764f177SMichael Neumann 
15696e6b862SMichael Neumann 	free(softlink_fmt);
1576764f177SMichael Neumann 	free(from);
1586764f177SMichael Neumann 	free(to);
1596b669ab4SMichael Neumann }
1606b669ab4SMichael Neumann 
1616b669ab4SMichael Neumann static
1626b669ab4SMichael Neumann void
1636b669ab4SMichael Neumann snapshot_usage(int exit_code)
1646b669ab4SMichael Neumann {
165f8052532SMichael Neumann 	fprintf(stderr, "hammer snapshot <snapshot-dir-in-filesystem>\n");
166f8052532SMichael Neumann 	fprintf(stderr, "hammer snapshot <filesystem> <snapshot-dir>\n");
1676b669ab4SMichael Neumann 	exit(exit_code);
1686b669ab4SMichael Neumann }
169