1 /* 2 * Copyright (c) 2008 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $DragonFly: src/sbin/hammer/cmd_snapshot.c,v 1.6 2008/06/28 14:18:00 swildner Exp $ 35 */ 36 37 #include "hammer.h" 38 #include <sys/param.h> 39 #include <sys/mount.h> 40 #include <sys/types.h> 41 #include <sys/stat.h> 42 #include <unistd.h> 43 #include <string.h> 44 #include <time.h> 45 46 #define DEFAULT_SNAPSHOT_NAME "snap-%Y%m%d-%H%M" 47 48 static void snapshot_usage(int exit_code); 49 50 /* 51 * snapshot <softlink-dir-in-filesystem> 52 * snapshot <filesystem> <softlink-dir> 53 */ 54 void 55 hammer_cmd_snapshot(char **av, int ac) 56 { 57 const char *filesystem; 58 const char *softlink_dir; 59 char *softlink_fmt; 60 struct statfs buf; 61 struct stat st; 62 struct hammer_ioc_synctid synctid; 63 char *from; 64 char *to; 65 66 if (ac == 1) { 67 filesystem = NULL; 68 softlink_dir = av[0]; 69 } else if (ac == 2) { 70 filesystem = av[0]; 71 softlink_dir = av[1]; 72 } else { 73 snapshot_usage(1); 74 } 75 76 if (stat(softlink_dir, &st) == 0) { 77 if (!S_ISDIR(st.st_mode)) 78 err(2, "File %s already exists", softlink_dir); 79 80 if (filesystem == NULL) { 81 if (statfs(softlink_dir, &buf) != 0) { 82 err(2, "Unable to determine filesystem of %s", 83 softlink_dir); 84 } 85 filesystem = buf.f_mntonname; 86 } 87 88 softlink_fmt = malloc(strlen(softlink_dir) + 1 + 1 + 89 sizeof(DEFAULT_SNAPSHOT_NAME)); 90 if (softlink_fmt == NULL) 91 err(2, "Failed to allocate string"); 92 93 strcpy(softlink_fmt, softlink_dir); 94 if (softlink_fmt[strlen(softlink_fmt)-1] != '/') 95 strcat(softlink_fmt, "/"); 96 strcat(softlink_fmt, DEFAULT_SNAPSHOT_NAME); 97 } else { 98 softlink_fmt = strdup(softlink_dir); 99 100 if (filesystem == NULL) { 101 /* 102 * strip-off last '/path' segment to get the softlink 103 * directory, which we need to determine the filesystem 104 * we are on. 105 */ 106 char *pos = strrchr(softlink_fmt, '/'); 107 if (pos != NULL) 108 *pos = '\0'; 109 110 if (stat(softlink_fmt, &st) != 0 || 111 !S_ISDIR(st.st_mode)) { 112 err(2, "Unable to determine softlink dir %s", 113 softlink_fmt); 114 } 115 if (statfs(softlink_fmt, &buf) != 0) { 116 err(2, "Unable to determine filesystem of %s", 117 softlink_fmt); 118 } 119 filesystem = buf.f_mntonname; 120 121 if (pos != NULL) 122 *pos = '/'; 123 } 124 } 125 126 /* 127 * Synctid 128 */ 129 bzero(&synctid, sizeof(synctid)); 130 synctid.op = HAMMER_SYNCTID_SYNC2; 131 int fd = open(filesystem, O_RDONLY); 132 if (fd < 0) 133 err(2, "Unable to open %s", filesystem); 134 if (ioctl(fd, HAMMERIOC_SYNCTID, &synctid) < 0) 135 err(2, "Synctid %s failed", filesystem); 136 close(fd); 137 138 asprintf(&from, "%s@@0x%016llx", filesystem, synctid.tid); 139 if (from == NULL) 140 err(2, "Couldn't generate string"); 141 142 int sz = strlen(softlink_fmt) + 50; 143 to = malloc(sz); 144 if (to == NULL) 145 err(2, "Failed to allocate string"); 146 147 time_t t = time(NULL); 148 if (strftime(to, sz, softlink_fmt, localtime(&t)) == 0) 149 err(2, "String buffer too small"); 150 151 if (symlink(from, to) != 0) 152 err(2, "Unable to symlink %s to %s", from, to); 153 154 printf("%s\n", to); 155 156 free(softlink_fmt); 157 free(from); 158 free(to); 159 } 160 161 static 162 void 163 snapshot_usage(int exit_code) 164 { 165 fprintf(stderr, "hammer snapshot <snapshot-dir-in-filesystem>\n"); 166 fprintf(stderr, "hammer snapshot <filesystem> <snapshot-dir>\n"); 167 exit(exit_code); 168 } 169