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 #include "dump.h"
28 #include <ftw.h>
29 #include <ulimit.h>
30
31 dev_t partial_dev;
32 static int partial;
33
34 static dev_t devfromopts(struct mntent *);
35 static int lf_mark_root(dev_t, char *);
36 static int lf_ftw_mark(const char *, const struct stat64 *, int);
37 static void markino(ino_t);
38
39 void
partial_check(void)40 partial_check(void)
41 {
42 struct mntent *mnt;
43 struct stat64 st;
44
45 if (stat64(disk, &st) < 0 ||
46 (st.st_mode & S_IFMT) == S_IFCHR ||
47 (st.st_mode & S_IFMT) == S_IFBLK)
48 return;
49
50 partial_dev = st.st_dev;
51
52 setmnttab();
53 while (mnt = getmnttab()) {
54 st.st_dev = devfromopts(mnt);
55 if (st.st_dev == NODEV &&
56 stat64(mnt->mnt_dir, &st) < 0)
57 continue;
58 if (partial_dev == st.st_dev) {
59 if (disk_dynamic) {
60 /* LINTED: disk is not NULL */
61 free(disk);
62 }
63 disk = rawname(mnt->mnt_fsname);
64 disk_dynamic = (disk != mnt->mnt_fsname);
65
66 partial = 1;
67 incno = '0';
68 uflag = 0;
69 return;
70 }
71 }
72 msg(gettext("`%s' is not on a locally mounted filesystem\n"), disk);
73 dumpabort();
74 /*NOTREACHED*/
75 }
76
77 /*
78 * The device id for the mount should be available in
79 * the mount option string as "dev=%04x". If it's there
80 * extract the device id and avoid having to stat.
81 */
82 static dev_t
devfromopts(struct mntent * mnt)83 devfromopts(struct mntent *mnt)
84 {
85 char *str;
86
87 str = hasmntopt(mnt, MNTINFO_DEV);
88 if (str != NULL && (str = strchr(str, '=')))
89 return ((dev_t)strtol(str + 1, (char **)NULL, 16));
90
91 return (NODEV);
92 }
93
94 int
partial_mark(int argc,char ** argv)95 partial_mark(int argc, char **argv)
96 {
97 char *path;
98 struct stat64 st;
99
100 if (partial == 0)
101 return (1);
102
103 while (--argc >= 0) {
104 path = *argv++;
105
106 if (stat64(path, &st) < 0 ||
107 st.st_dev != partial_dev) {
108 msg(gettext("`%s' is not on dump device `%s'\n"),
109 path, disk);
110 dumpabort();
111 /*NOTREACHED*/
112 }
113
114 if (lf_mark_root(partial_dev, path)) {
115 msg(gettext(
116 "Cannot find filesystem mount point for `%s'\n"),
117 path);
118 dumpabort();
119 /*NOTREACHED*/
120 }
121
122 /* LINTED this ulimit will always be < INT_MAX */
123 if (lf_lftw(path, lf_ftw_mark, (int)ulimit(UL_GDESLIM, 0) / 2)
124 < 0) {
125 int saverr = errno;
126 msg(gettext("Error in %s (%s)\n"),
127 "ftw", strerror(saverr));
128 dumpabort();
129 /*NOTREACHED*/
130 }
131 }
132
133 return (0);
134 }
135
136 /* mark directories between target and root */
137 static int
lf_mark_root(dev_t dev,char * path)138 lf_mark_root(dev_t dev, char *path)
139 {
140 struct stat64 st;
141 char dotdot[MAXPATHLEN + 16];
142 char *slash;
143
144 if (strlen(path) > sizeof (dotdot))
145 return (1);
146
147 (void) strcpy(dotdot, path);
148
149 if (stat64(dotdot, &st) < 0)
150 return (1);
151
152 /* if target is a regular file, find directory */
153 if ((st.st_mode & S_IFMT) != S_IFDIR)
154 if (slash = strrchr(dotdot, '/'))
155 /* "/file" -> "/" */
156 if (slash == dotdot)
157 slash[1] = 0;
158 /* "dir/file" -> "dir" */
159 else
160 slash[0] = 0;
161 else
162 /* "file" -> "." */
163 (void) strcpy(dotdot, ".");
164
165 /* keep marking parent until we hit mount point */
166 do {
167 if (stat64(dotdot, &st) < 0 ||
168 (st.st_mode & S_IFMT) != S_IFDIR ||
169 st.st_dev != dev)
170 return (1);
171 markino(st.st_ino);
172 if (strlen(dotdot) > (sizeof (dotdot) - 4))
173 return (1);
174 (void) strcat(dotdot, "/..");
175 } while (st.st_ino != 2);
176
177 return (0);
178 }
179
180 /*ARGSUSED*/
181 static int
lf_ftw_mark(const char * name,const struct stat64 * st,int flag)182 lf_ftw_mark(const char *name, const struct stat64 *st, int flag)
183 {
184 if (flag != FTW_NS) {
185 /* LINTED ufs only uses the lower 32 bits */
186 markino((ino_t)st->st_ino);
187 }
188 return (0);
189 }
190
191 static void
markino(ino_t i)192 markino(ino_t i)
193 {
194 struct dinode *dp;
195
196 dp = getino(ino = i);
197 mark(dp);
198 }
199