1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright (c) 1998,2001 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include "dump.h"
30#include <ftw.h>
31#include <ulimit.h>
32
33static int partial;
34
35#ifdef __STDC__
36static dev_t devfromopts(struct mntent *);
37static int lf_mark_root(dev_t, char *);
38static int lf_ftw_mark(const char *, const struct stat64 *, int);
39static void markino(ino_t);
40#else
41static dev_t devfromopts();
42static int lf_mark_root();
43static int lf_ftw_mark();
44static void markino();
45#endif
46
47void
48#ifdef __STDC__
49partial_check(void)
50#else
51partial_check()
52#endif
53{
54	struct mntent *mnt;
55	struct stat64 st;
56
57	if (stat64(disk, &st) < 0 ||
58	    (st.st_mode & S_IFMT) == S_IFCHR ||
59	    (st.st_mode & S_IFMT) == S_IFBLK)
60		return;
61
62	partial_dev = st.st_dev;
63
64	setmnttab();
65	while (mnt = getmnttab()) {
66		st.st_dev = devfromopts(mnt);
67		if (st.st_dev == NODEV &&
68		    stat64(mnt->mnt_dir, &st) < 0)
69			continue;
70		if (partial_dev == st.st_dev) {
71			if (disk_dynamic) {
72				/* LINTED: disk is not NULL */
73				free(disk);
74			}
75			disk = rawname(mnt->mnt_fsname);
76			disk_dynamic = (disk != mnt->mnt_fsname);
77
78			partial = 1;
79			incno = '0';
80			uflag = 0;
81			return;
82		}
83	}
84	msg(gettext("`%s' is not on a locally mounted filesystem\n"), disk);
85	dumpabort();
86	/*NOTREACHED*/
87}
88
89/*
90 *  The device id for the mount should be available in
91 *  the mount option string as "dev=%04x".  If it's there
92 *  extract the device id and avoid having to stat.
93 */
94static dev_t
95devfromopts(mnt)
96	struct mntent *mnt;
97{
98	char *str;
99
100	str = hasmntopt(mnt, MNTINFO_DEV);
101	if (str != NULL && (str = strchr(str, '=')))
102		return ((dev_t)strtol(str + 1, (char **)NULL, 16));
103
104	return (NODEV);
105}
106
107int
108partial_mark(argc, argv)
109	int argc;
110	char **argv;
111{
112	char *path;
113	struct stat64 st;
114
115	if (partial == 0)
116		return (1);
117
118	while (--argc >= 0) {
119		path = *argv++;
120
121		if (stat64(path, &st) < 0 ||
122			st.st_dev != partial_dev) {
123			msg(gettext("`%s' is not on dump device `%s'\n"),
124				path, disk);
125			dumpabort();
126			/*NOTREACHED*/
127		}
128
129		if (lf_mark_root(partial_dev, path)) {
130			msg(gettext(
131			    "Cannot find filesystem mount point for `%s'\n"),
132			    path);
133			dumpabort();
134			/*NOTREACHED*/
135		}
136
137		/* LINTED this ulimit will always be < INT_MAX */
138		if (lf_lftw(path, lf_ftw_mark, (int)ulimit(UL_GDESLIM, 0) / 2)
139		    < 0) {
140			int saverr = errno;
141			msg(gettext("Error in %s (%s)\n"),
142				"ftw", strerror(saverr));
143			dumpabort();
144			/*NOTREACHED*/
145		}
146	}
147
148	return (0);
149}
150
151/* mark directories between target and root */
152static int
153lf_mark_root(dev, path)
154	dev_t dev;
155	char *path;
156{
157	struct stat64 st;
158	char dotdot[MAXPATHLEN + 16];
159	char *slash;
160
161	if (strlen(path) > sizeof (dotdot))
162		return (1);
163
164	(void) strcpy(dotdot, path);
165
166	if (stat64(dotdot, &st) < 0)
167		return (1);
168
169	/* if target is a regular file, find directory */
170	if ((st.st_mode & S_IFMT) != S_IFDIR)
171		if (slash = strrchr(dotdot, '/'))
172			/* "/file" -> "/" */
173			if (slash == dotdot)
174				slash[1] = 0;
175			/* "dir/file" -> "dir" */
176			else
177				slash[0] = 0;
178		else
179			/* "file" -> "." */
180			(void) strcpy(dotdot, ".");
181
182	/* keep marking parent until we hit mount point */
183	do {
184		if (stat64(dotdot, &st) < 0 ||
185			(st.st_mode & S_IFMT) != S_IFDIR ||
186			st.st_dev != dev)
187			return (1);
188		markino(st.st_ino);
189		if (strlen(dotdot) > (sizeof (dotdot) - 4))
190			return (1);
191		(void) strcat(dotdot, "/..");
192	} while (st.st_ino != 2);
193
194	return (0);
195}
196
197/*ARGSUSED*/
198static int
199lf_ftw_mark(name, st, flag)
200#ifdef __STDC__
201	const char *name;
202	const struct stat64 *st;
203#else
204	char *name;
205	struct stat64 *st;
206#endif
207	int flag;
208{
209	if (flag != FTW_NS) {
210		/* LINTED ufs only uses the lower 32 bits */
211		markino((ino_t)st->st_ino);
212	}
213	return (0);
214}
215
216static void
217markino(i)
218	ino_t i;
219{
220	struct dinode *dp;
221
222	dp = getino(ino = i);
223	mark(dp);
224}
225