1148197Smarks/*-
2148197Smarks * Copyright (c) 2005 Mark Santcroos <marks@freebsd.org>
3148197Smarks *
4148197Smarks * Redistribution and use in source and binary forms, with or without
5148197Smarks * modification, are permitted provided that the following conditions
6148197Smarks * are met:
7148197Smarks * 1. Redistributions of source code must retain the above copyright
8148197Smarks *    notice, this list of conditions and the following disclaimer.
9148197Smarks * 2. Redistributions in binary form must reproduce the above copyright
10148197Smarks *    notice, this list of conditions and the following disclaimer in the
11148197Smarks *    documentation and/or other materials provided with the distribution.
12148197Smarks *
13148197Smarks * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14148197Smarks * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15148197Smarks * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16148197Smarks * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17148197Smarks * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18148197Smarks * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19148197Smarks * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20148197Smarks * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21148197Smarks * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22148197Smarks * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23148197Smarks *
24148197Smarks * $FreeBSD: releng/10.3/usr.sbin/snapinfo/snapinfo.c 241015 2012-09-27 23:31:19Z mdf $
25148197Smarks *
26148197Smarks */
27148197Smarks
28148197Smarks#include <sys/param.h>
29148197Smarks#include <sys/mount.h>
30148197Smarks
31148197Smarks#include <ufs/ufs/dinode.h>
32148197Smarks#include <ufs/ffs/fs.h>
33148197Smarks
34148197Smarks#include <errno.h>
35148197Smarks#include <ftw.h>
36148197Smarks#include <libufs.h>
37241015Smdf#include <stdint.h>
38148197Smarks#include <stdio.h>
39148197Smarks#include <stdlib.h>
40148197Smarks#include <string.h>
41148197Smarks#include <unistd.h>
42148197Smarks
43227260Sedstatic void	find_inum(char *path);
44227260Sedstatic void	usage(void);
45227260Sedstatic int	compare_function(const char *, const struct stat *,
46227260Sed		    int, struct FTW *);
47227260Sedstatic int	find_snapshot(struct statfs *sfs);
48148197Smarks
49227260Sedstatic int	verbose;
50227260Sedstatic int	cont_search;
51227260Sedstatic uint32_t	inode;
52148197Smarks
53148197Smarksint
54148197Smarksmain(int argc, char **argv)
55148197Smarks{
56148197Smarks	char *path;
57148197Smarks	struct stat st;
58148197Smarks	struct statfs *mntbuf;
59148197Smarks	int all = 0, ch, done = 0, fscount, n;
60148197Smarks
61148197Smarks	while ((ch = getopt(argc, argv, "adv")) != -1) {
62148197Smarks		switch (ch) {
63148197Smarks		case 'a':
64148197Smarks			all++;
65148197Smarks			break;
66148197Smarks		case 'd':
67148197Smarks			/* continue to search when matching inode is found
68148197Smarks			 * this feature is not documented */
69148197Smarks			cont_search++;
70148197Smarks			break;
71148197Smarks		case 'v':
72148197Smarks			verbose++;
73148197Smarks			break;
74148197Smarks		default:
75148197Smarks			usage();
76148197Smarks		}
77148197Smarks	}
78148197Smarks
79148197Smarks	argc -= optind;
80148197Smarks	argv += optind;
81148197Smarks
82148197Smarks	if ((all == 0 && argc != 1) || (all == 1 && argc > 0))
83148197Smarks		usage();
84148197Smarks
85148197Smarks	if (!all) {
86167633Spjd		char resolved[PATH_MAX];
87167633Spjd
88148197Smarks		path = *argv;
89167633Spjd		/*
90167633Spjd		 * mount(8) use realpath(3) before mounting file system,
91167633Spjd		 * so let's do the same with the given path.
92167633Spjd		 */
93167633Spjd		if (realpath(path, resolved) == NULL ||	/* can create full path */
94167633Spjd		    stat(resolved, &st) == -1 ||	/* is it stat'able */
95167633Spjd		    !S_ISDIR(st.st_mode)) {		/* is it a directory */
96148197Smarks			usage();
97167633Spjd		}
98167633Spjd		path = resolved;
99148197Smarks	}
100148197Smarks
101148197Smarks	fscount = getmntinfo(&mntbuf, MNT_WAIT);
102148197Smarks	for (n = 0; n < fscount; n++) {
103148197Smarks		if (!strncmp(mntbuf[n].f_fstypename, "ufs", 3)) {
104167626Spjd			if (all || strcmp(path, mntbuf[n].f_mntonname) == 0) {
105167626Spjd				find_snapshot(&mntbuf[n]);
106167626Spjd				done++;
107167626Spjd			}
108148197Smarks		}
109148197Smarks	}
110148197Smarks
111167626Spjd	if (done == 0)
112148197Smarks		usage();
113148197Smarks
114148197Smarks	return (0);
115148197Smarks}
116148197Smarks
117227260Sedstatic int
118167626Spjdfind_snapshot(struct statfs *sfs)
119148197Smarks{
120148197Smarks	struct uufsd disk;
121148197Smarks	int j, snapcount = 0;
122148197Smarks
123167626Spjd	if (ufs_disk_fillout(&disk, sfs->f_mntfromname) == -1)
124148197Smarks		perror("ufs_disk_fillout");
125148197Smarks
126148197Smarks	if (verbose)
127148197Smarks		printf("%s mounted on %s\n", disk.d_name, disk.d_fs.fs_fsmnt);
128148197Smarks
129148197Smarks	for (j = 0; j < FSMAXSNAP; j++) {
130148197Smarks		if (disk.d_fs.fs_snapinum[j]) {
131148197Smarks			inode = disk.d_fs.fs_snapinum[j];
132167626Spjd			find_inum(sfs->f_mntonname);
133148197Smarks			snapcount++;
134148197Smarks		}
135148197Smarks	}
136148197Smarks
137148197Smarks	if (!snapcount && verbose)
138148197Smarks		printf("\tno snapshots found\n");
139148197Smarks
140148197Smarks	return 0;
141148197Smarks}
142148197Smarks
143227260Sedstatic int
144148197Smarkscompare_function(const char *path, const struct stat *st, int flags,
145201388Sed    struct FTW * ftwv __unused)
146148197Smarks{
147148197Smarks
148148197Smarks	if (flags == FTW_F && st->st_ino == inode) {
149148197Smarks		if (verbose)
150148197Smarks			printf("\tsnapshot ");
151148197Smarks		printf("%s", path);
152148197Smarks		if (verbose)
153241015Smdf			printf(" (inode %ju)", (uintmax_t)st->st_ino);
154148197Smarks		printf("\n");
155148197Smarks		if (!cont_search)
156148197Smarks			return (EEXIST);
157148197Smarks	}
158148197Smarks
159148197Smarks	return (0);
160148197Smarks}
161148197Smarks
162227260Sedstatic void
163148197Smarksfind_inum(char *path)
164148197Smarks{
165148197Smarks	int ret;
166148197Smarks
167148197Smarks	ret = nftw(path, compare_function, 1, FTW_PHYS|FTW_MOUNT);
168148197Smarks	if (ret != EEXIST && ret != 0) {
169148197Smarks		perror("ftw");
170148197Smarks		exit(ret);
171148197Smarks	}
172148197Smarks}
173148197Smarks
174227260Sedstatic void
175148197Smarksusage(void)
176148197Smarks{
177148197Smarks
178148197Smarks	printf("usage: snapinfo [-v] -a\n");
179148197Smarks	printf("       snapinfo [-v] mountpoint\n");
180148197Smarks	exit(1);
181148197Smarks}
182