xref: /illumos-gate/usr/src/cmd/backup/dump/dumponline.c (revision e5803b76927480e8f9b67b22201c484ccf4c2bcf)
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
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__
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__
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
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 *
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
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
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__
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__
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