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