1217044Snwhitehorn/*- 2217044Snwhitehorn * Copyright (c) 2005 Mark Santcroos <marks@freebsd.org> 3217044Snwhitehorn * 4217044Snwhitehorn * Redistribution and use in source and binary forms, with or without 5217044Snwhitehorn * modification, are permitted provided that the following conditions 6217044Snwhitehorn * are met: 7217044Snwhitehorn * 1. Redistributions of source code must retain the above copyright 8217044Snwhitehorn * notice, this list of conditions and the following disclaimer. 9217044Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 10217044Snwhitehorn * notice, this list of conditions and the following disclaimer in the 11217044Snwhitehorn * documentation and/or other materials provided with the distribution. 12217044Snwhitehorn * 13217044Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14217044Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15217044Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16217044Snwhitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17217044Snwhitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18217044Snwhitehorn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19217044Snwhitehorn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20217044Snwhitehorn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21217044Snwhitehorn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22217044Snwhitehorn * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23217044Snwhitehorn * 24217044Snwhitehorn * $FreeBSD$ 25217044Snwhitehorn * 26217044Snwhitehorn */ 27217044Snwhitehorn 28217044Snwhitehorn#include <sys/param.h> 29217044Snwhitehorn#include <sys/mount.h> 30217044Snwhitehorn 31217044Snwhitehorn#include <ufs/ufs/dinode.h> 32217044Snwhitehorn#include <ufs/ffs/fs.h> 33217044Snwhitehorn 34217044Snwhitehorn#include <errno.h> 35217044Snwhitehorn#include <ftw.h> 36217044Snwhitehorn#include <libufs.h> 37217044Snwhitehorn#include <stdint.h> 38217044Snwhitehorn#include <stdio.h> 39217044Snwhitehorn#include <stdlib.h> 40217044Snwhitehorn#include <string.h> 41217044Snwhitehorn#include <unistd.h> 42217044Snwhitehorn 43217044Snwhitehornstatic void find_inum(char *path); 44217044Snwhitehornstatic void usage(void); 45217044Snwhitehornstatic int compare_function(const char *, const struct stat *, 46217044Snwhitehorn int, struct FTW *); 47217044Snwhitehornstatic int find_snapshot(struct statfs *sfs); 48217044Snwhitehorn 49217044Snwhitehornstatic int verbose; 50217044Snwhitehornstatic int cont_search; 51217044Snwhitehornstatic uint32_t inode; 52217044Snwhitehorn 53217044Snwhitehornint 54217044Snwhitehornmain(int argc, char **argv) 55217044Snwhitehorn{ 56217044Snwhitehorn char *path; 57217044Snwhitehorn struct stat st; 58217044Snwhitehorn struct statfs *mntbuf; 59217044Snwhitehorn int all = 0, ch, done = 0, fscount, n; 60217044Snwhitehorn 61217044Snwhitehorn while ((ch = getopt(argc, argv, "adv")) != -1) { 62217044Snwhitehorn switch (ch) { 63217044Snwhitehorn case 'a': 64217044Snwhitehorn all++; 65217044Snwhitehorn break; 66217044Snwhitehorn case 'd': 67217044Snwhitehorn /* continue to search when matching inode is found 68217044Snwhitehorn * this feature is not documented */ 69217044Snwhitehorn cont_search++; 70217044Snwhitehorn break; 71224106Snwhitehorn case 'v': 72224857Snwhitehorn verbose++; 73224106Snwhitehorn break; 74224857Snwhitehorn default: 75224857Snwhitehorn usage(); 76224857Snwhitehorn } 77224857Snwhitehorn } 78224106Snwhitehorn 79217044Snwhitehorn argc -= optind; 80217044Snwhitehorn argv += optind; 81 82 if ((all == 0 && argc != 1) || (all == 1 && argc > 0)) 83 usage(); 84 85 if (!all) { 86 char resolved[PATH_MAX]; 87 88 path = *argv; 89 /* 90 * mount(8) use realpath(3) before mounting file system, 91 * so let's do the same with the given path. 92 */ 93 if (realpath(path, resolved) == NULL || /* can create full path */ 94 stat(resolved, &st) == -1 || /* is it stat'able */ 95 !S_ISDIR(st.st_mode)) { /* is it a directory */ 96 usage(); 97 } 98 path = resolved; 99 } 100 101 fscount = getmntinfo(&mntbuf, MNT_WAIT); 102 for (n = 0; n < fscount; n++) { 103 if (!strncmp(mntbuf[n].f_fstypename, "ufs", 3)) { 104 if (all || strcmp(path, mntbuf[n].f_mntonname) == 0) { 105 find_snapshot(&mntbuf[n]); 106 done++; 107 } 108 } 109 } 110 111 if (done == 0) 112 usage(); 113 114 return (0); 115} 116 117static int 118find_snapshot(struct statfs *sfs) 119{ 120 struct uufsd disk; 121 int j, snapcount = 0; 122 123 if (ufs_disk_fillout(&disk, sfs->f_mntfromname) == -1) 124 perror("ufs_disk_fillout"); 125 126 if (verbose) 127 printf("%s mounted on %s\n", disk.d_name, disk.d_fs.fs_fsmnt); 128 129 for (j = 0; j < FSMAXSNAP; j++) { 130 if (disk.d_fs.fs_snapinum[j]) { 131 inode = disk.d_fs.fs_snapinum[j]; 132 find_inum(sfs->f_mntonname); 133 snapcount++; 134 } 135 } 136 137 if (!snapcount && verbose) 138 printf("\tno snapshots found\n"); 139 140 return 0; 141} 142 143static int 144compare_function(const char *path, const struct stat *st, int flags, 145 struct FTW * ftwv __unused) 146{ 147 148 if (flags == FTW_F && st->st_ino == inode) { 149 if (verbose) 150 printf("\tsnapshot "); 151 printf("%s", path); 152 if (verbose) 153 printf(" (inode %ju)", (uintmax_t)st->st_ino); 154 printf("\n"); 155 if (!cont_search) 156 return (EEXIST); 157 } 158 159 return (0); 160} 161 162static void 163find_inum(char *path) 164{ 165 int ret; 166 167 ret = nftw(path, compare_function, 1, FTW_PHYS|FTW_MOUNT); 168 if (ret != EEXIST && ret != 0) { 169 perror("ftw"); 170 exit(ret); 171 } 172} 173 174static void 175usage(void) 176{ 177 178 printf("usage: snapinfo [-v] -a\n"); 179 printf(" snapinfo [-v] mountpoint\n"); 180 exit(1); 181} 182