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