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