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
onsigbus(int sig)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
allocino(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
freeino(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
resetino(ino_t ino)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 *
unrawname(char * cp)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
lf_ismounted(char * devname,char * dirname)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
mapfile(int fd,off_t offset,off_t bytes,int fetch)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
unmapfile(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
activepass(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