xref: /freebsd/usr.sbin/snapinfo/snapinfo.c (revision a64729f5077d77e13b9497cb33ecb3c82e606ee8)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2005 Mark Santcroos <marks@freebsd.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  */
27 
28 #include <sys/param.h>
29 #include <sys/mount.h>
30 
31 #include <ufs/ufs/dinode.h>
32 #include <ufs/ffs/fs.h>
33 
34 #include <errno.h>
35 #include <ftw.h>
36 #include <libufs.h>
37 #include <stdint.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 
43 static void	find_inum(char *path);
44 static void	usage(void);
45 static int	compare_function(const char *, const struct stat *,
46 		    int, struct FTW *);
47 static int	find_snapshot(struct statfs *sfs);
48 
49 static int	verbose;
50 static int	cont_search;
51 static uint32_t	inode;
52 
53 int
54 main(int argc, char **argv)
55 {
56 	char *path;
57 	struct stat st;
58 	struct statfs *mntbuf;
59 	int all = 0, ch, done = 0, fscount, n;
60 
61 	while ((ch = getopt(argc, argv, "adv")) != -1) {
62 		switch (ch) {
63 		case 'a':
64 			all++;
65 			break;
66 		case 'd':
67 			/* continue to search when matching inode is found
68 			 * this feature is not documented */
69 			cont_search++;
70 			break;
71 		case 'v':
72 			verbose++;
73 			break;
74 		default:
75 			usage();
76 		}
77 	}
78 
79 	argc -= optind;
80 	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 
117 static int
118 find_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 
143 static int
144 compare_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 
162 static void
163 find_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 
174 static void
175 usage(void)
176 {
177 
178 	printf("usage: snapinfo [-v] -a\n");
179 	printf("       snapinfo [-v] mountpoint\n");
180 	exit(1);
181 }
182