1 /* 2 * Copyright (c) 2015 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Antonio Huete <tuxillo@quantumachine.net> 6 * by Matthew Dillon <dillon@backplane.com> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 3. Neither the name of The DragonFly Project nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific, prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 37 #include <assert.h> 38 #include <stdio.h> 39 #include <strings.h> 40 #include <string.h> 41 #include <stdlib.h> 42 #include <fcntl.h> 43 #include <errno.h> 44 #include <unistd.h> 45 46 #include "libhammer.h" 47 48 int 49 libhammer_pfs_get_snapshots(libhammer_fsinfo_t fip, libhammer_pfsinfo_t pip) 50 { 51 struct hammer_snapshot_data *snapdata = NULL; 52 struct hammer_ioc_snapshot snap; 53 libhammer_snapinfo_t sip; 54 libhammer_pfsinfo_t pfs0; 55 char *path = NULL; 56 int ret = 0; 57 int fd; 58 u_int i; 59 60 assert(pip != NULL); 61 assert(fip != NULL); 62 63 /* 64 * Still need a path to open so, when not mounted, try 65 * to figure out the PFS path access in order to open(2) 66 * Note that this will fail for slave PFS that were created 67 * with pfs-slave directive since they don't have any transaction 68 * recorded and nlookup can't find them. For those we simply 69 * return the error in the head structure of libhammer_pfsinfo_t 70 * for the caller to handle the situation. 71 */ 72 pfs0 = libhammer_get_first_pfs(fip); 73 if (pip->mountedon == NULL) 74 libhammer_pfs_canonical_path(pfs0->mountedon, pip, &path); 75 else 76 path = strdup(pip->mountedon); 77 78 if (path == NULL || (fd = open(path, O_RDONLY)) < 0) { 79 pip->head.error = errno; 80 ret = -1; 81 goto out; 82 } 83 84 bzero(&snap, sizeof(snap)); 85 86 /* 87 * Loop while there are snapshots returned from the ioctl(2) call. 88 * 89 * For more information on how the snapshots are returned 90 * to userland please check sys/vfs/hammer/hammer_ioctl.c 91 */ 92 do { 93 if (ioctl(fd, HAMMERIOC_GET_SNAPSHOT, &snap) < 0) { 94 pip->head.error = errno; 95 ret = -1; 96 close(fd); 97 goto out; 98 } 99 for (i = 0; i < snap.count; i++) { 100 snapdata = &snap.snaps[i]; 101 sip = _libhammer_malloc(sizeof(*sip)); 102 sip->tid = snapdata->tid; 103 sip->ts = snapdata->ts; 104 if (strlen(snapdata->label)) 105 sprintf(sip->label, "%s", snapdata->label); 106 else 107 sip->label[0] = '\0'; 108 TAILQ_INSERT_TAIL(&pip->list_snap, sip, entries); 109 pip->snapcount++; 110 } 111 } while (snap.head.error == 0 && snap.count); 112 close(fd); 113 114 out: 115 if (path) 116 free(path); 117 118 return (ret); 119 } 120 121 void 122 libhammer_pfs_free_snapshots(libhammer_pfsinfo_t pip) 123 { 124 struct libhammer_snapinfo *si; 125 126 while(!TAILQ_EMPTY(&pip->list_snap)) { 127 si = TAILQ_FIRST(&pip->list_snap); 128 TAILQ_REMOVE(&pip->list_snap, si, entries); 129 free(si); 130 } 131 } 132