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) 1991,1996,1998 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 <math.h>
31 #include <limits.h>
32
33 /*
34 * Uncomment if using mmap'ing of files for pre-fetch.
35 * #define ENABLE_MMAP 1
36 */
37
38 struct inodesc {
39 ino_t id_inumber; /* inode number */
40 long id_gen; /* generation number */
41 struct inodesc *id_next; /* next on linked list */
42 };
43
44 static struct inodesc ilist; /* list of used inodesc structs */
45 static struct inodesc *last; /* last inodesc init'd or matched */
46 static struct inodesc *freeinodesc; /* free list of inodesc structs */
47 static struct inodesc **ialloc; /* allocated chunks, for freeing */
48 static int nchunks; /* number of allocations */
49
50 #ifdef ENABLE_MMAP /* XXX part of mmap support */
51 /*
52 * If an mmap'ed file is truncated as it is being dumped or
53 * faulted in, we are delivered a SIGBUS.
54 */
55 static jmp_buf truncate_buf;
56 static void (*savebus)();
57 static int incopy;
58
59 #ifdef __STDC__
60 static void onsigbus(int);
61 #else
62 static void onsigbus();
63 #endif
64
65 #endif /* ENABLE_MMAP */
66
67 #ifdef DEBUG
68 extern int xflag;
69 #endif
70
71 #ifdef ENABLE_MMAP /* XXX part of mmap support */
72 static void
onsigbus(sig)73 onsigbus(sig)
74 int sig;
75 {
76 if (!incopy) {
77 dumpabort();
78 /*NOTREACHED*/
79 }
80 incopy = 0;
81 longjmp(truncate_buf, 1);
82 /*NOTREACHED*/
83 }
84 #endif /* ENABLE_MMAP */
85
86 void
87 #ifdef __STDC__
allocino(void)88 allocino(void)
89 #else
90 allocino()
91 #endif
92 {
93 ino_t maxino;
94 size_t nused;
95
96 maxino = (unsigned)(sblock->fs_ipg * sblock->fs_ncg);
97 if (maxino > ULONG_MAX) {
98 msg(gettext("allocino: filesystem too large\n"));
99 dumpabort();
100 /*NOTREACHED*/
101 }
102 /* LINTED maxino guaranteed to fit into a size_t by above test */
103 nused = maxino - sblock->fs_cstotal.cs_nifree;
104 freeinodesc = (struct inodesc *)xcalloc(nused, sizeof (*freeinodesc));
105 if (freeinodesc == (struct inodesc *)0) {
106 msg(gettext("%s: out of memory\n"), "allocino");
107 dumpabort();
108 /*NOTREACHED*/
109 }
110 last = &ilist;
111 ialloc =
112 (struct inodesc **)xmalloc(2*sizeof (*ialloc));
113 ialloc[0] = freeinodesc;
114 ialloc[1] = (struct inodesc *)0;
115 nchunks = 1;
116 }
117
118 void
119 #ifdef __STDC__
freeino(void)120 freeino(void)
121 #else
122 freeino()
123 #endif
124 {
125 int i;
126
127 if (ialloc == (struct inodesc **)0)
128 return;
129 for (i = 0; i < nchunks; i++)
130 if (ialloc[i] != 0)
131 free(ialloc[i]);
132 free(ialloc);
133 ialloc = (struct inodesc **)0;
134 }
135
136 void
resetino(ino)137 resetino(ino)
138 ino_t ino;
139 {
140 last = ilist.id_next;
141 while (last && last->id_inumber < ino)
142 last = last->id_next;
143 }
144
145 char *
unrawname(cp)146 unrawname(cp)
147 char *cp;
148 {
149 char *dp;
150 extern char *getfullblkname();
151
152 dp = getfullblkname(cp);
153 if (dp == 0)
154 return (0);
155 if (*dp == '\0') {
156 free(dp);
157 return (0);
158 }
159 if (dp == cp) /* caller wants to always free() dp */
160 dp = strdup(cp);
161
162 return (dp);
163 }
164
165 /*
166 * Determine if specified device is mounted at
167 * specified mount point. Returns 1 if mounted,
168 * 0 if not mounted, -1 on error.
169 */
170 int
lf_ismounted(devname,dirname)171 lf_ismounted(devname, dirname)
172 char *devname; /* name of device (raw or block) */
173 char *dirname; /* name of f/s mount point */
174 {
175 struct stat64 st;
176 char *blockname; /* name of block device */
177 dev_t dev;
178 int saverr;
179
180 if ((blockname = unrawname(devname)) == NULL) {
181 msg(gettext("Cannot obtain block name from `%s'\n"), devname);
182 return (-1);
183 }
184 if (stat64(blockname, &st) < 0) {
185 saverr = errno;
186 msg(gettext("Cannot obtain status of device `%s': %s\n"),
187 blockname, strerror(saverr));
188 free(blockname);
189 return (-1);
190 }
191 free(blockname);
192 dev = st.st_rdev;
193 if (stat64(dirname, &st) < 0) {
194 saverr = errno;
195 msg(gettext("Cannot obtain status of device `%s': %s\n"),
196 dirname, strerror(saverr));
197 return (-1);
198 }
199 if (dev == st.st_dev)
200 return (1);
201 return (0);
202 }
203
204 #ifdef ENABLE_MMAP /* XXX mapped-file support */
205 #define MINMAPSIZE 1024*1024
206 #define MAXMAPSIZE 1024*1024*32
207
208 static caddr_t mapbase; /* base of mapped data */
209 static caddr_t mapend; /* last byte of mapped data */
210 static size_t mapsize; /* amount of mapped data */
211 /*
212 * Map a file prior to dumping and start faulting in its
213 * pages. Stop if we catch a signal indicating our turn
214 * to dump has arrived. If the file is truncated out from
215 * under us, immediately return.
216 * NB: the base of the mapped data may not coincide
217 * exactly to the requested offset, due to alignment
218 * constraints.
219 */
220 caddr_t
mapfile(fd,offset,bytes,fetch)221 mapfile(fd, offset, bytes, fetch)
222 int fd;
223 off_t offset; /* offset within file */
224 off_t bytes; /* number of bytes to map */
225 int fetch; /* start faulting in pages */
226 {
227 /*LINTED [c used during pre-fetch faulting]*/
228 volatile char c, *p;
229 int stride = (int)sysconf(_SC_PAGESIZE);
230 extern int caught; /* pre-fetch until set */
231 caddr_t mapstart; /* beginning of file's mapped data */
232 off_t mapoffset; /* page-aligned offset */
233 int saverr;
234
235 mapbase = mapend = (caddr_t)0;
236
237 if (bytes == 0)
238 return ((caddr_t)0);
239 /*
240 * mmap the file for reading
241 */
242 mapoffset = offset & ~(stride - 1);
243 /* LINTED: "bytes" will always fit into a size_t */
244 mapsize = bytes + (offset - mapoffset);
245 if (mapsize > MAXMAPSIZE)
246 mapsize = MAXMAPSIZE;
247 while ((mapbase = mmap((caddr_t)0, mapsize, PROT_READ,
248 MAP_SHARED, fd, mapoffset)) == (caddr_t)-1 &&
249 errno == ENOMEM && mapsize >= MINMAPSIZE) {
250 /*
251 * Due to address space limitations, we
252 * may not be able to map as much as we want.
253 */
254 mapsize /= 2; /* exponential back-off */
255 }
256
257 if (mapbase == (caddr_t)-1) {
258 saverr = errno;
259 msg(gettext("Cannot map file at inode `%lu' into memory: %s\n"),
260 ino, strerror(saverr));
261 /* XXX why not call dumpailing() here? */
262 if (!query(gettext(
263 "Do you want to attempt to continue? (\"yes\" or \"no\") "))) {
264 dumpabort();
265 /*NOTREACHED*/
266 }
267 mapbase = (caddr_t)0;
268 return ((caddr_t)0);
269 }
270
271 (void) madvise(mapbase, mapsize, MADV_SEQUENTIAL);
272 mapstart = mapbase + (offset - mapoffset);
273 mapend = mapbase + (mapsize - 1);
274
275 if (!fetch)
276 return (mapstart);
277
278 if (setjmp(truncate_buf) == 0) {
279 savebus = signal(SIGBUS, onsigbus);
280 /*
281 * Touch each page to pre-fetch by faulting. At least
282 * one of c or *p must be declared volatile, lest the
283 * optimizer eliminate the assignment in the loop.
284 */
285 incopy = 1;
286 for (p = mapbase; !caught && p <= mapend; p += stride) {
287 /* LINTED: c is used for its side-effects */
288 c = *p;
289 }
290 incopy = 0;
291 }
292 #ifdef DEBUG
293 else
294 /* XGETTEXT: #ifdef DEBUG only */
295 msg(gettext(
296 "FILE TRUNCATED (fault): Interrupting pre-fetch\n"));
297 #endif
298 (void) signal(SIGBUS, savebus);
299 return (mapstart);
300 }
301
302 void
303 #ifdef __STDC__
unmapfile(void)304 unmapfile(void)
305 #else
306 unmapfile()
307 #endif
308 {
309 if (mapbase) {
310 /* XXX we're unmapping it, so what does this gain us? */
311 (void) msync(mapbase, mapsize, MS_ASYNC|MS_INVALIDATE);
312 (void) munmap(mapbase, mapsize);
313 mapbase = (caddr_t)0;
314 }
315 }
316 #endif /* ENABLE_MMAP */
317
318 void
319 #ifdef __STDC__
activepass(void)320 activepass(void)
321 #else
322 activepass()
323 #endif
324 {
325 static int passno = 1; /* active file pass number */
326 char *ext, *old;
327 char buf[3000];
328 static char defext[] = ".retry";
329
330 if (pipeout) {
331 msg(gettext("Cannot re-dump active files to `%s'\n"), tape);
332 dumpabort();
333 /*NOTREACHED*/
334 }
335
336 if (active > 1)
337 (void) snprintf(buf, sizeof (buf), gettext(
338 "%d files were active and will be re-dumped\n"), active);
339 else
340 (void) snprintf(buf, sizeof (buf), gettext(
341 "1 file was active and will be re-dumped\n"));
342 msg(buf);
343
344 doingactive++;
345 active = 0;
346 reset(); /* reset tape params */
347 spcl.c_ddate = spcl.c_date; /* chain with last dump/pass */
348
349 /*
350 * If archiving, create a new
351 * archive file.
352 */
353 if (archivefile) {
354 old = archivefile;
355
356 ext = strstr(old, defext);
357 if (ext != (char *)NULL)
358 *ext = '\0'; /* just want the base name */
359
360 /* The two is for the trailing \0 and rounding up log10() */
361 archivefile = xmalloc(strlen(old) + strlen(defext) +
362 (int)log10((double)passno) + 2);
363
364 /* Always fits */
365 (void) sprintf(archivefile, "%s%s%d", old, defext, passno);
366 free(old);
367 }
368
369 if (tapeout) {
370 if (isrewind(to)) {
371 /*
372 * A "rewind" tape device. When we do
373 * the close, we will lose our position.
374 * Be nice and switch volumes.
375 */
376 (void) snprintf(buf, sizeof (buf), gettext(
377 "Warning - cannot dump active files to rewind device `%s'\n"),
378 tape);
379 msg(buf);
380 close_rewind();
381 changevol();
382 } else {
383 trewind();
384 doposition = 0;
385 filenum++;
386 }
387 } else {
388 /*
389 * Not a tape. Do a volume switch.
390 * This will advance to the next file
391 * if using a sequence of files, next
392 * diskette if using diskettes, or
393 * let the user move the old file out
394 * of the way.
395 */
396 close_rewind();
397 changevol(); /* switch files */
398 }
399 (void) snprintf(buf, sizeof (buf), gettext(
400 "Dumping active files (retry pass %d) to `%s'\n"), passno, tape);
401 msg(buf);
402 passno++;
403 }
404