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$
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>
37148197Smarks#include <stdio.h>
38148197Smarks#include <stdlib.h>
39148197Smarks#include <string.h>
40148197Smarks#include <unistd.h>
41148197Smarks
42148197Smarksvoid	find_inum(char *path);
43148197Smarksvoid	usage(void);
44148197Smarksint	compare_function(const char *, const struct stat *, int, struct FTW *);
45167626Spjdint	find_snapshot(struct statfs *sfs);
46148197Smarks
47148197Smarksint verbose;
48148197Smarksint cont_search;
49148197Smarksuint32_t inode;
50148197Smarks
51148197Smarksint
52148197Smarksmain(int argc, char **argv)
53148197Smarks{
54148197Smarks	char *path;
55148197Smarks	struct stat st;
56148197Smarks	struct statfs *mntbuf;
57148197Smarks	int all = 0, ch, done = 0, fscount, n;
58148197Smarks
59148197Smarks	while ((ch = getopt(argc, argv, "adv")) != -1) {
60148197Smarks		switch (ch) {
61148197Smarks		case 'a':
62148197Smarks			all++;
63148197Smarks			break;
64148197Smarks		case 'd':
65148197Smarks			/* continue to search when matching inode is found
66148197Smarks			 * this feature is not documented */
67148197Smarks			cont_search++;
68148197Smarks			break;
69148197Smarks		case 'v':
70148197Smarks			verbose++;
71148197Smarks			break;
72148197Smarks		default:
73148197Smarks			usage();
74148197Smarks		}
75148197Smarks	}
76148197Smarks
77148197Smarks	argc -= optind;
78148197Smarks	argv += optind;
79148197Smarks
80148197Smarks	if ((all == 0 && argc != 1) || (all == 1 && argc > 0))
81148197Smarks		usage();
82148197Smarks
83148197Smarks	if (!all) {
84167633Spjd		char resolved[PATH_MAX];
85167633Spjd
86148197Smarks		path = *argv;
87167633Spjd		/*
88167633Spjd		 * mount(8) use realpath(3) before mounting file system,
89167633Spjd		 * so let's do the same with the given path.
90167633Spjd		 */
91167633Spjd		if (realpath(path, resolved) == NULL ||	/* can create full path */
92167633Spjd		    stat(resolved, &st) == -1 ||	/* is it stat'able */
93167633Spjd		    !S_ISDIR(st.st_mode)) {		/* is it a directory */
94148197Smarks			usage();
95167633Spjd		}
96167633Spjd		path = resolved;
97148197Smarks	}
98148197Smarks
99148197Smarks	fscount = getmntinfo(&mntbuf, MNT_WAIT);
100148197Smarks	for (n = 0; n < fscount; n++) {
101148197Smarks		if (!strncmp(mntbuf[n].f_fstypename, "ufs", 3)) {
102167626Spjd			if (all || strcmp(path, mntbuf[n].f_mntonname) == 0) {
103167626Spjd				find_snapshot(&mntbuf[n]);
104167626Spjd				done++;
105167626Spjd			}
106148197Smarks		}
107148197Smarks	}
108148197Smarks
109167626Spjd	if (done == 0)
110148197Smarks		usage();
111148197Smarks
112148197Smarks	return (0);
113148197Smarks}
114148197Smarks
115148197Smarksint
116167626Spjdfind_snapshot(struct statfs *sfs)
117148197Smarks{
118148197Smarks	struct uufsd disk;
119148197Smarks	int j, snapcount = 0;
120148197Smarks
121167626Spjd	if (ufs_disk_fillout(&disk, sfs->f_mntfromname) == -1)
122148197Smarks		perror("ufs_disk_fillout");
123148197Smarks
124148197Smarks	if (verbose)
125148197Smarks		printf("%s mounted on %s\n", disk.d_name, disk.d_fs.fs_fsmnt);
126148197Smarks
127148197Smarks	for (j = 0; j < FSMAXSNAP; j++) {
128148197Smarks		if (disk.d_fs.fs_snapinum[j]) {
129148197Smarks			inode = disk.d_fs.fs_snapinum[j];
130167626Spjd			find_inum(sfs->f_mntonname);
131148197Smarks			snapcount++;
132148197Smarks		}
133148197Smarks	}
134148197Smarks
135148197Smarks	if (!snapcount && verbose)
136148197Smarks		printf("\tno snapshots found\n");
137148197Smarks
138148197Smarks	return 0;
139148197Smarks}
140148197Smarks
141148197Smarksint
142148197Smarkscompare_function(const char *path, const struct stat *st, int flags,
143201388Sed    struct FTW * ftwv __unused)
144148197Smarks{
145148197Smarks
146148197Smarks	if (flags == FTW_F && st->st_ino == inode) {
147148197Smarks		if (verbose)
148148197Smarks			printf("\tsnapshot ");
149148197Smarks		printf("%s", path);
150148197Smarks		if (verbose)
151148197Smarks			printf(" (inode %d)", st->st_ino);
152148197Smarks		printf("\n");
153148197Smarks		if (!cont_search)
154148197Smarks			return (EEXIST);
155148197Smarks	}
156148197Smarks
157148197Smarks	return (0);
158148197Smarks}
159148197Smarks
160148197Smarksvoid
161148197Smarksfind_inum(char *path)
162148197Smarks{
163148197Smarks	int ret;
164148197Smarks
165148197Smarks	ret = nftw(path, compare_function, 1, FTW_PHYS|FTW_MOUNT);
166148197Smarks	if (ret != EEXIST && ret != 0) {
167148197Smarks		perror("ftw");
168148197Smarks		exit(ret);
169148197Smarks	}
170148197Smarks}
171148197Smarks
172148197Smarksvoid
173148197Smarksusage(void)
174148197Smarks{
175148197Smarks
176148197Smarks	printf("usage: snapinfo [-v] -a\n");
177148197Smarks	printf("       snapinfo [-v] mountpoint\n");
178148197Smarks	exit(1);
179148197Smarks}
180