1 1.75 andvar /* $NetBSD: tape.c,v 1.75 2024/02/05 22:08:04 andvar Exp $ */ 2 1.16 cgd 3 1.10 cgd /* 4 1.11 mycroft * Copyright (c) 1983, 1993 5 1.11 mycroft * The Regents of the University of California. All rights reserved. 6 1.10 cgd * (c) UNIX System Laboratories, Inc. 7 1.10 cgd * All or some portions of this file are derived from material licensed 8 1.10 cgd * to the University of California by American Telephone and Telegraph 9 1.10 cgd * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10 1.10 cgd * the permission of UNIX System Laboratories, Inc. 11 1.10 cgd * 12 1.10 cgd * Redistribution and use in source and binary forms, with or without 13 1.10 cgd * modification, are permitted provided that the following conditions 14 1.10 cgd * are met: 15 1.10 cgd * 1. Redistributions of source code must retain the above copyright 16 1.10 cgd * notice, this list of conditions and the following disclaimer. 17 1.10 cgd * 2. Redistributions in binary form must reproduce the above copyright 18 1.10 cgd * notice, this list of conditions and the following disclaimer in the 19 1.10 cgd * documentation and/or other materials provided with the distribution. 20 1.49 agc * 3. Neither the name of the University nor the names of its contributors 21 1.10 cgd * may be used to endorse or promote products derived from this software 22 1.10 cgd * without specific prior written permission. 23 1.10 cgd * 24 1.10 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 1.10 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 1.10 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 1.10 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 1.10 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 1.10 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 1.10 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 1.10 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 1.10 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 1.10 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 1.10 cgd * SUCH DAMAGE. 35 1.10 cgd */ 36 1.10 cgd 37 1.28 lukem #include <sys/cdefs.h> 38 1.10 cgd #ifndef lint 39 1.16 cgd #if 0 40 1.29 lukem static char sccsid[] = "@(#)tape.c 8.9 (Berkeley) 5/1/95"; 41 1.16 cgd #else 42 1.75 andvar __RCSID("$NetBSD: tape.c,v 1.75 2024/02/05 22:08:04 andvar Exp $"); 43 1.16 cgd #endif 44 1.10 cgd #endif /* not lint */ 45 1.10 cgd 46 1.10 cgd #include <sys/param.h> 47 1.10 cgd #include <sys/file.h> 48 1.10 cgd #include <sys/ioctl.h> 49 1.10 cgd #include <sys/mtio.h> 50 1.10 cgd #include <sys/stat.h> 51 1.71 christos #include <sys/extattr.h> 52 1.71 christos #define _ACL_PRIVATE 53 1.71 christos #include <sys/acl.h> 54 1.10 cgd 55 1.71 christos #include <ufs/ufs/extattr.h> 56 1.11 mycroft #include <ufs/ufs/dinode.h> 57 1.10 cgd #include <protocols/dumprestore.h> 58 1.10 cgd 59 1.51 bouyer #include <err.h> 60 1.10 cgd #include <errno.h> 61 1.26 lukem #include <paths.h> 62 1.10 cgd #include <setjmp.h> 63 1.10 cgd #include <stdio.h> 64 1.10 cgd #include <stdlib.h> 65 1.10 cgd #include <string.h> 66 1.36 kleink #include <time.h> 67 1.10 cgd #include <unistd.h> 68 1.10 cgd 69 1.50 enami #include <md5.h> 70 1.57 christos #include <rmd160.h> 71 1.50 enami #include <sha1.h> 72 1.50 enami 73 1.10 cgd #include "restore.h" 74 1.10 cgd #include "extern.h" 75 1.10 cgd 76 1.28 lukem static u_int32_t fssize = MAXBSIZE; 77 1.10 cgd static int mt = -1; 78 1.10 cgd static int pipein = 0; 79 1.10 cgd static char magtape[BUFSIZ]; 80 1.10 cgd static int blkcnt; 81 1.10 cgd static int numtrec; 82 1.10 cgd static char *tapebuf; 83 1.10 cgd static union u_spcl endoftapemark; 84 1.28 lukem static int blksread; /* blocks read since last header */ 85 1.28 lukem static int tpblksread = 0; /* TP_BSIZE blocks read */ 86 1.28 lukem static int tapesread; 87 1.10 cgd static jmp_buf restart; 88 1.10 cgd static int gettingfile = 0; /* restart has a valid frame */ 89 1.47 taca #ifdef RRESTORE 90 1.53 christos static const char *host = NULL; 91 1.47 taca #endif 92 1.10 cgd 93 1.10 cgd static int ofile; 94 1.10 cgd static char lnkbuf[MAXPATHLEN + 1]; 95 1.10 cgd static int pathlen; 96 1.10 cgd 97 1.10 cgd int oldinofmt; /* old inode format conversion required */ 98 1.10 cgd int Bcvt; /* Swap Bytes (for CCI or sun) */ 99 1.10 cgd 100 1.50 enami const struct digest_desc *ddesc; 101 1.50 enami 102 1.50 enami static union digest_context { 103 1.65 dholland MD5_CTX dc_MD5; 104 1.65 dholland SHA1_CTX dc_SHA1; 105 1.65 dholland RMD160_CTX dc_RMD160; 106 1.50 enami } dcontext; 107 1.50 enami 108 1.64 dholland /* 109 1.64 dholland * 32 for md5; 40 for sha1 and rmd160 110 1.64 dholland * plus a null terminator. 111 1.64 dholland */ 112 1.64 dholland #define DIGEST_BUFFER_SIZE (40 + 1) 113 1.50 enami 114 1.10 cgd #define FLUSHTAPEBUF() blkcnt = ntrec + 1 115 1.10 cgd 116 1.71 christos const char *namespace_names[] = EXTATTR_NAMESPACE_NAMES; 117 1.71 christos 118 1.71 christos 119 1.48 fvdl union u_ospcl { 120 1.48 fvdl char dummy[TP_BSIZE]; 121 1.48 fvdl struct s_ospcl { 122 1.48 fvdl int32_t c_type; 123 1.48 fvdl int32_t c_date; 124 1.48 fvdl int32_t c_ddate; 125 1.48 fvdl int32_t c_volume; 126 1.48 fvdl int32_t c_tapea; 127 1.48 fvdl u_int16_t c_inumber; 128 1.48 fvdl int32_t c_magic; 129 1.48 fvdl int32_t c_checksum; 130 1.48 fvdl struct odinode { 131 1.48 fvdl unsigned short odi_mode; 132 1.48 fvdl u_int16_t odi_nlink; 133 1.48 fvdl u_int16_t odi_uid; 134 1.48 fvdl u_int16_t odi_gid; 135 1.48 fvdl int32_t odi_size; 136 1.48 fvdl int32_t odi_rdev; 137 1.48 fvdl char odi_addr[36]; 138 1.48 fvdl int32_t odi_atime; 139 1.48 fvdl int32_t odi_mtime; 140 1.48 fvdl int32_t odi_ctime; 141 1.48 fvdl } c_odinode; 142 1.48 fvdl int32_t c_count; 143 1.48 fvdl char c_addr[256]; 144 1.48 fvdl } s_ospcl; 145 1.48 fvdl }; 146 1.48 fvdl 147 1.52 xtraeme static void accthdr(struct s_spcl *); 148 1.52 xtraeme static int checksum(int *); 149 1.52 xtraeme static void findinode(struct s_spcl *); 150 1.52 xtraeme static void findtapeblksize(void); 151 1.71 christos static char *setupextattr(size_t); 152 1.71 christos static void xtrattr(char *, size_t); 153 1.71 christos static void skiphole(void (*)(char *, size_t), volatile size_t *); 154 1.59 hannken static void getbitmap(char **); 155 1.52 xtraeme static int gethead(struct s_spcl *); 156 1.52 xtraeme static void readtape(char *); 157 1.52 xtraeme static void setdumpnum(void); 158 1.52 xtraeme static void terminateinput(void); 159 1.71 christos static void xtrfile(char *, size_t); 160 1.71 christos static void xtrlnkfile(char *, size_t); 161 1.71 christos __dead static void xtrlnkskip(char *, size_t); 162 1.71 christos static void xtrskip(char *, size_t); 163 1.52 xtraeme static void swap_header(struct s_spcl *); 164 1.52 xtraeme static void swap_old_header(struct s_ospcl *); 165 1.10 cgd 166 1.65 dholland //////////////////////////////////////////////////////////// 167 1.65 dholland // thunks for type correctness 168 1.65 dholland 169 1.65 dholland #define WRAP(alg) \ 170 1.65 dholland static void \ 171 1.65 dholland do_##alg##Init(void *ctx) \ 172 1.65 dholland { \ 173 1.65 dholland alg##Init(ctx); \ 174 1.65 dholland } \ 175 1.65 dholland \ 176 1.65 dholland static void \ 177 1.65 dholland do_##alg##Update(union digest_context *ctx, \ 178 1.65 dholland const void *buf, unsigned len) \ 179 1.65 dholland { \ 180 1.65 dholland alg##Update(&ctx->dc_##alg, buf, len); \ 181 1.65 dholland } \ 182 1.65 dholland \ 183 1.65 dholland static char * \ 184 1.65 dholland do_##alg##End(void *ctx, char *str) \ 185 1.65 dholland { \ 186 1.65 dholland return alg##End(ctx, str); \ 187 1.65 dholland } 188 1.65 dholland 189 1.65 dholland WRAP(MD5); 190 1.65 dholland WRAP(SHA1); 191 1.65 dholland WRAP(RMD160); 192 1.65 dholland 193 1.65 dholland static const struct digest_desc digest_descs[] = { 194 1.65 dholland { "MD5", 195 1.65 dholland do_MD5Init, 196 1.65 dholland do_MD5Update, 197 1.65 dholland do_MD5End, }, 198 1.65 dholland { "SHA1", 199 1.65 dholland do_SHA1Init, 200 1.65 dholland do_SHA1Update, 201 1.65 dholland do_SHA1End, }, 202 1.65 dholland { "RMD160", 203 1.65 dholland do_RMD160Init, 204 1.65 dholland do_RMD160Update, 205 1.65 dholland do_RMD160End, }, 206 1.65 dholland { .dd_name = NULL }, 207 1.65 dholland }; 208 1.65 dholland 209 1.65 dholland //////////////////////////////////////////////////////////// 210 1.65 dholland 211 1.50 enami const struct digest_desc * 212 1.52 xtraeme digest_lookup(const char *name) 213 1.50 enami { 214 1.50 enami const struct digest_desc *dd; 215 1.50 enami 216 1.50 enami for (dd = digest_descs; dd->dd_name != NULL; dd++) 217 1.50 enami if (strcasecmp(dd->dd_name, name) == 0) 218 1.50 enami return (dd); 219 1.50 enami 220 1.50 enami return (NULL); 221 1.50 enami } 222 1.50 enami 223 1.10 cgd /* 224 1.10 cgd * Set up an input source 225 1.10 cgd */ 226 1.10 cgd void 227 1.53 christos setinput(const char *source) 228 1.10 cgd { 229 1.53 christos char *cp; 230 1.10 cgd FLUSHTAPEBUF(); 231 1.10 cgd if (bflag) 232 1.10 cgd newtapebuf(ntrec); 233 1.10 cgd else 234 1.10 cgd newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC); 235 1.10 cgd terminal = stdin; 236 1.10 cgd 237 1.10 cgd #ifdef RRESTORE 238 1.53 christos if ((cp = strchr(source, ':')) != NULL) { 239 1.10 cgd host = source; 240 1.53 christos /* Ok, because const strings don't have : */ 241 1.53 christos *cp++ = '\0'; 242 1.53 christos source = cp; 243 1.10 cgd if (rmthost(host) == 0) 244 1.15 mycroft exit(1); 245 1.10 cgd } else 246 1.10 cgd #endif 247 1.10 cgd if (strcmp(source, "-") == 0) { 248 1.10 cgd /* 249 1.10 cgd * Since input is coming from a pipe we must establish 250 1.10 cgd * our own connection to the terminal. 251 1.10 cgd */ 252 1.10 cgd terminal = fopen(_PATH_TTY, "r"); 253 1.10 cgd if (terminal == NULL) { 254 1.10 cgd (void)fprintf(stderr, "cannot open %s: %s\n", 255 1.10 cgd _PATH_TTY, strerror(errno)); 256 1.10 cgd terminal = fopen(_PATH_DEVNULL, "r"); 257 1.10 cgd if (terminal == NULL) { 258 1.10 cgd (void)fprintf(stderr, "cannot open %s: %s\n", 259 1.10 cgd _PATH_DEVNULL, strerror(errno)); 260 1.15 mycroft exit(1); 261 1.10 cgd } 262 1.10 cgd } 263 1.10 cgd pipein++; 264 1.10 cgd } 265 1.10 cgd (void) strcpy(magtape, source); 266 1.10 cgd } 267 1.10 cgd 268 1.10 cgd void 269 1.52 xtraeme newtapebuf(long size) 270 1.10 cgd { 271 1.35 mrg static int tapebufsize = -1; 272 1.10 cgd 273 1.10 cgd ntrec = size; 274 1.10 cgd if (size <= tapebufsize) 275 1.10 cgd return; 276 1.10 cgd if (tapebuf != NULL) 277 1.10 cgd free(tapebuf); 278 1.10 cgd tapebuf = malloc(size * TP_BSIZE); 279 1.10 cgd if (tapebuf == NULL) { 280 1.10 cgd fprintf(stderr, "Cannot allocate space for tape buffer\n"); 281 1.15 mycroft exit(1); 282 1.10 cgd } 283 1.10 cgd tapebufsize = size; 284 1.10 cgd } 285 1.10 cgd 286 1.10 cgd /* 287 1.10 cgd * Verify that the tape drive can be accessed and 288 1.10 cgd * that it actually is a dump tape. 289 1.10 cgd */ 290 1.10 cgd void 291 1.52 xtraeme setup(void) 292 1.10 cgd { 293 1.10 cgd int i, j, *ip; 294 1.10 cgd struct stat stbuf; 295 1.10 cgd 296 1.10 cgd vprintf(stdout, "Verify tape and initialize maps\n"); 297 1.10 cgd #ifdef RRESTORE 298 1.10 cgd if (host) 299 1.60 matt mt = rmtopen(magtape, 0, 0); 300 1.10 cgd else 301 1.10 cgd #endif 302 1.10 cgd if (pipein) 303 1.10 cgd mt = 0; 304 1.10 cgd else 305 1.10 cgd mt = open(magtape, O_RDONLY, 0); 306 1.10 cgd if (mt < 0) { 307 1.10 cgd fprintf(stderr, "%s: %s\n", magtape, strerror(errno)); 308 1.15 mycroft exit(1); 309 1.10 cgd } 310 1.10 cgd volno = 1; 311 1.10 cgd setdumpnum(); 312 1.10 cgd FLUSHTAPEBUF(); 313 1.10 cgd if (!pipein && !bflag) 314 1.10 cgd findtapeblksize(); 315 1.10 cgd if (gethead(&spcl) == FAIL) { 316 1.10 cgd blkcnt--; /* push back this block */ 317 1.10 cgd blksread--; 318 1.10 cgd tpblksread--; 319 1.10 cgd cvtflag++; 320 1.10 cgd if (gethead(&spcl) == FAIL) { 321 1.10 cgd fprintf(stderr, "Tape is not a dump tape\n"); 322 1.15 mycroft exit(1); 323 1.10 cgd } 324 1.10 cgd fprintf(stderr, "Converting to new file system format.\n"); 325 1.10 cgd } 326 1.10 cgd if (pipein) { 327 1.48 fvdl endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : 328 1.48 fvdl FS_UFS2_MAGIC; 329 1.10 cgd endoftapemark.s_spcl.c_type = TS_END; 330 1.10 cgd ip = (int *)&endoftapemark; 331 1.10 cgd j = sizeof(union u_spcl) / sizeof(int); 332 1.10 cgd i = 0; 333 1.10 cgd do 334 1.10 cgd i += *ip++; 335 1.10 cgd while (--j); 336 1.10 cgd endoftapemark.s_spcl.c_checksum = CHECKSUM - i; 337 1.10 cgd } 338 1.10 cgd if (vflag || command == 't') 339 1.10 cgd printdumpinfo(); 340 1.10 cgd dumptime = spcl.c_ddate; 341 1.10 cgd dumpdate = spcl.c_date; 342 1.10 cgd if (stat(".", &stbuf) < 0) { 343 1.10 cgd fprintf(stderr, "cannot stat .: %s\n", strerror(errno)); 344 1.15 mycroft exit(1); 345 1.10 cgd } 346 1.22 cgd if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE) 347 1.10 cgd fssize = stbuf.st_blksize; 348 1.10 cgd if (((fssize - 1) & fssize) != 0) { 349 1.10 cgd fprintf(stderr, "bad block size %d\n", fssize); 350 1.15 mycroft exit(1); 351 1.10 cgd } 352 1.10 cgd if (spcl.c_volume != 1) { 353 1.10 cgd fprintf(stderr, "Tape is not volume 1 of the dump\n"); 354 1.15 mycroft exit(1); 355 1.10 cgd } 356 1.10 cgd if (gethead(&spcl) == FAIL) { 357 1.10 cgd dprintf(stdout, "header read failed at %d blocks\n", blksread); 358 1.10 cgd panic("no header after volume mark!\n"); 359 1.10 cgd } 360 1.10 cgd findinode(&spcl); 361 1.10 cgd if (spcl.c_type != TS_CLRI) { 362 1.10 cgd fprintf(stderr, "Cannot find file removal list\n"); 363 1.15 mycroft exit(1); 364 1.10 cgd } 365 1.59 hannken getbitmap(&usedinomap); 366 1.59 hannken getbitmap(&dumpmap); 367 1.14 mycroft /* 368 1.14 mycroft * If there may be whiteout entries on the tape, pretend that the 369 1.14 mycroft * whiteout inode exists, so that the whiteout entries can be 370 1.14 mycroft * extracted. 371 1.14 mycroft */ 372 1.14 mycroft if (oldinofmt == 0) 373 1.67 dholland SETINO(UFS_WINO, dumpmap); 374 1.10 cgd } 375 1.10 cgd 376 1.10 cgd /* 377 1.10 cgd * Prompt user to load a new dump volume. 378 1.10 cgd * "Nextvol" is the next suggested volume to use. 379 1.10 cgd * This suggested volume is enforced when doing full 380 1.75 andvar * or incremental restores, but can be overridden by 381 1.10 cgd * the user when only extracting a subset of the files. 382 1.10 cgd */ 383 1.10 cgd void 384 1.52 xtraeme getvol(int nextvol) 385 1.10 cgd { 386 1.28 lukem int newvol, savecnt, wantnext, i; 387 1.10 cgd union u_spcl tmpspcl; 388 1.10 cgd # define tmpbuf tmpspcl.s_spcl 389 1.10 cgd char buf[TP_BSIZE]; 390 1.10 cgd 391 1.28 lukem newvol = savecnt = wantnext = 0; 392 1.10 cgd if (nextvol == 1) { 393 1.10 cgd tapesread = 0; 394 1.10 cgd gettingfile = 0; 395 1.10 cgd } 396 1.10 cgd if (pipein) { 397 1.10 cgd if (nextvol != 1) 398 1.10 cgd panic("Changing volumes on pipe input?\n"); 399 1.10 cgd if (volno == 1) 400 1.10 cgd return; 401 1.10 cgd goto gethdr; 402 1.10 cgd } 403 1.10 cgd savecnt = blksread; 404 1.10 cgd again: 405 1.10 cgd if (pipein) 406 1.15 mycroft exit(1); /* pipes do not get a second chance */ 407 1.10 cgd if (command == 'R' || command == 'r' || curfile.action != SKIP) { 408 1.10 cgd newvol = nextvol; 409 1.10 cgd wantnext = 1; 410 1.10 cgd } else { 411 1.10 cgd newvol = 0; 412 1.10 cgd wantnext = 0; 413 1.10 cgd } 414 1.10 cgd while (newvol <= 0) { 415 1.10 cgd if (tapesread == 0) { 416 1.10 cgd fprintf(stderr, "%s%s%s%s%s", 417 1.10 cgd "You have not read any tapes yet.\n", 418 1.10 cgd "Unless you know which volume your", 419 1.10 cgd " file(s) are on you should start\n", 420 1.10 cgd "with the last volume and work", 421 1.24 cjs " towards the first.\n"); 422 1.38 lukem fprintf(stderr, 423 1.38 lukem "(Use 1 for the first volume/tape, etc.)\n"); 424 1.10 cgd } else { 425 1.10 cgd fprintf(stderr, "You have read volumes"); 426 1.10 cgd strcpy(buf, ": "); 427 1.10 cgd for (i = 1; i < 32; i++) 428 1.10 cgd if (tapesread & (1 << i)) { 429 1.10 cgd fprintf(stderr, "%s%d", buf, i); 430 1.10 cgd strcpy(buf, ", "); 431 1.10 cgd } 432 1.10 cgd fprintf(stderr, "\n"); 433 1.10 cgd } 434 1.10 cgd do { 435 1.10 cgd fprintf(stderr, "Specify next volume #: "); 436 1.10 cgd (void) fflush(stderr); 437 1.10 cgd (void) fgets(buf, BUFSIZ, terminal); 438 1.10 cgd } while (!feof(terminal) && buf[0] == '\n'); 439 1.10 cgd if (feof(terminal)) 440 1.15 mycroft exit(1); 441 1.10 cgd newvol = atoi(buf); 442 1.10 cgd if (newvol <= 0) { 443 1.10 cgd fprintf(stderr, 444 1.10 cgd "Volume numbers are positive numerics\n"); 445 1.10 cgd } 446 1.10 cgd } 447 1.10 cgd if (newvol == volno) { 448 1.10 cgd tapesread |= 1 << volno; 449 1.10 cgd return; 450 1.10 cgd } 451 1.10 cgd closemt(); 452 1.10 cgd fprintf(stderr, "Mount tape volume %d\n", newvol); 453 1.10 cgd fprintf(stderr, "Enter ``none'' if there are no more tapes\n"); 454 1.10 cgd fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape); 455 1.10 cgd (void) fflush(stderr); 456 1.10 cgd (void) fgets(buf, BUFSIZ, terminal); 457 1.10 cgd if (feof(terminal)) 458 1.15 mycroft exit(1); 459 1.10 cgd if (!strcmp(buf, "none\n")) { 460 1.10 cgd terminateinput(); 461 1.10 cgd return; 462 1.10 cgd } 463 1.10 cgd if (buf[0] != '\n') { 464 1.10 cgd (void) strcpy(magtape, buf); 465 1.10 cgd magtape[strlen(magtape) - 1] = '\0'; 466 1.10 cgd } 467 1.10 cgd #ifdef RRESTORE 468 1.10 cgd if (host) 469 1.60 matt mt = rmtopen(magtape, 0, 0); 470 1.10 cgd else 471 1.10 cgd #endif 472 1.10 cgd mt = open(magtape, O_RDONLY, 0); 473 1.10 cgd 474 1.10 cgd if (mt == -1) { 475 1.10 cgd fprintf(stderr, "Cannot open %s\n", magtape); 476 1.10 cgd volno = -1; 477 1.10 cgd goto again; 478 1.10 cgd } 479 1.10 cgd gethdr: 480 1.10 cgd volno = newvol; 481 1.10 cgd setdumpnum(); 482 1.10 cgd FLUSHTAPEBUF(); 483 1.10 cgd if (gethead(&tmpbuf) == FAIL) { 484 1.10 cgd dprintf(stdout, "header read failed at %d blocks\n", blksread); 485 1.10 cgd fprintf(stderr, "tape is not dump tape\n"); 486 1.10 cgd volno = 0; 487 1.10 cgd goto again; 488 1.10 cgd } 489 1.10 cgd if (tmpbuf.c_volume != volno) { 490 1.38 lukem fprintf(stderr, 491 1.38 lukem "Volume mismatch: expecting %d, tape header claims it is %d\n", 492 1.38 lukem volno, tmpbuf.c_volume); 493 1.10 cgd volno = 0; 494 1.10 cgd goto again; 495 1.10 cgd } 496 1.10 cgd if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) { 497 1.44 lukem time_t ttime = tmpbuf.c_date; 498 1.10 cgd fprintf(stderr, "Wrong dump date\n\tgot: %s", 499 1.44 lukem ctime(&ttime)); 500 1.10 cgd fprintf(stderr, "\twanted: %s", ctime(&dumpdate)); 501 1.10 cgd volno = 0; 502 1.10 cgd goto again; 503 1.10 cgd } 504 1.10 cgd tapesread |= 1 << volno; 505 1.10 cgd blksread = savecnt; 506 1.10 cgd /* 507 1.10 cgd * If continuing from the previous volume, skip over any 508 1.10 cgd * blocks read already at the end of the previous volume. 509 1.10 cgd * 510 1.10 cgd * If coming to this volume at random, skip to the beginning 511 1.10 cgd * of the next record. 512 1.10 cgd */ 513 1.10 cgd dprintf(stdout, "read %ld recs, tape starts with %ld\n", 514 1.28 lukem (long)tpblksread, (long)tmpbuf.c_firstrec); 515 1.10 cgd if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) { 516 1.10 cgd if (!wantnext) { 517 1.10 cgd tpblksread = tmpbuf.c_firstrec; 518 1.10 cgd for (i = tmpbuf.c_count; i > 0; i--) 519 1.10 cgd readtape(buf); 520 1.10 cgd } else if (tmpbuf.c_firstrec > 0 && 521 1.10 cgd tmpbuf.c_firstrec < tpblksread - 1) { 522 1.10 cgd /* 523 1.10 cgd * -1 since we've read the volume header 524 1.10 cgd */ 525 1.10 cgd i = tpblksread - tmpbuf.c_firstrec - 1; 526 1.10 cgd dprintf(stderr, "Skipping %d duplicate record%s.\n", 527 1.10 cgd i, i > 1 ? "s" : ""); 528 1.10 cgd while (--i >= 0) 529 1.10 cgd readtape(buf); 530 1.10 cgd } 531 1.10 cgd } 532 1.10 cgd if (curfile.action == USING) { 533 1.10 cgd if (volno == 1) 534 1.10 cgd panic("active file into volume 1\n"); 535 1.10 cgd return; 536 1.10 cgd } 537 1.10 cgd /* 538 1.10 cgd * Skip up to the beginning of the next record 539 1.10 cgd */ 540 1.10 cgd if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) 541 1.10 cgd for (i = tmpbuf.c_count; i > 0; i--) 542 1.10 cgd readtape(buf); 543 1.10 cgd (void) gethead(&spcl); 544 1.10 cgd findinode(&spcl); 545 1.10 cgd if (gettingfile) { 546 1.10 cgd gettingfile = 0; 547 1.10 cgd longjmp(restart, 1); 548 1.10 cgd } 549 1.10 cgd } 550 1.10 cgd 551 1.10 cgd /* 552 1.10 cgd * Handle unexpected EOF. 553 1.10 cgd */ 554 1.10 cgd static void 555 1.52 xtraeme terminateinput(void) 556 1.10 cgd { 557 1.10 cgd 558 1.10 cgd if (gettingfile && curfile.action == USING) { 559 1.10 cgd printf("Warning: %s %s\n", 560 1.10 cgd "End-of-input encountered while extracting", curfile.name); 561 1.10 cgd } 562 1.10 cgd curfile.name = "<name unknown>"; 563 1.10 cgd curfile.action = UNKNOWN; 564 1.48 fvdl curfile.mode = 0; 565 1.10 cgd curfile.ino = maxino; 566 1.10 cgd if (gettingfile) { 567 1.10 cgd gettingfile = 0; 568 1.10 cgd longjmp(restart, 1); 569 1.10 cgd } 570 1.10 cgd } 571 1.10 cgd 572 1.10 cgd /* 573 1.10 cgd * handle multiple dumps per tape by skipping forward to the 574 1.10 cgd * appropriate one. 575 1.10 cgd */ 576 1.10 cgd static void 577 1.52 xtraeme setdumpnum(void) 578 1.10 cgd { 579 1.10 cgd struct mtop tcom; 580 1.10 cgd 581 1.10 cgd if (dumpnum == 1 || volno != 1) 582 1.10 cgd return; 583 1.10 cgd if (pipein) { 584 1.10 cgd fprintf(stderr, "Cannot have multiple dumps on pipe input\n"); 585 1.15 mycroft exit(1); 586 1.10 cgd } 587 1.10 cgd tcom.mt_op = MTFSF; 588 1.10 cgd tcom.mt_count = dumpnum - 1; 589 1.10 cgd #ifdef RRESTORE 590 1.10 cgd if (host) 591 1.10 cgd rmtioctl(MTFSF, dumpnum - 1); 592 1.10 cgd else 593 1.10 cgd #endif 594 1.10 cgd if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0) 595 1.10 cgd fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno)); 596 1.10 cgd } 597 1.10 cgd 598 1.10 cgd void 599 1.52 xtraeme printdumpinfo(void) 600 1.10 cgd { 601 1.44 lukem time_t ttime; 602 1.44 lukem 603 1.44 lukem ttime = spcl.c_date; 604 1.44 lukem fprintf(stdout, "Dump date: %s", ctime(&ttime)); 605 1.44 lukem ttime = spcl.c_ddate; 606 1.10 cgd fprintf(stdout, "Dumped from: %s", 607 1.44 lukem (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&ttime)); 608 1.10 cgd fprintf(stderr, "Level %d dump of %s on %s:%s\n", 609 1.39 sommerfe spcl.c_level, spcl.c_filesys, 610 1.39 sommerfe *spcl.c_host? spcl.c_host: "[unknown]", spcl.c_dev); 611 1.10 cgd fprintf(stderr, "Label: %s\n", spcl.c_label); 612 1.51 bouyer 613 1.51 bouyer if (Mtreefile) { 614 1.51 bouyer ttime = spcl.c_date; 615 1.51 bouyer fprintf(Mtreefile, "#Dump date: %s", ctime(&ttime)); 616 1.51 bouyer ttime = spcl.c_ddate; 617 1.51 bouyer fprintf(Mtreefile, "#Dumped from: %s", 618 1.51 bouyer (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&ttime)); 619 1.51 bouyer fprintf(Mtreefile, "#Level %d dump of %s on %s:%s\n", 620 1.51 bouyer spcl.c_level, spcl.c_filesys, 621 1.51 bouyer *spcl.c_host? spcl.c_host: "[unknown]", spcl.c_dev); 622 1.51 bouyer fprintf(Mtreefile, "#Label: %s\n", spcl.c_label); 623 1.51 bouyer fprintf(Mtreefile, "/set uname=root gname=wheel\n"); 624 1.51 bouyer if (ferror(Mtreefile)) 625 1.51 bouyer err(1, "error writing to mtree file"); 626 1.51 bouyer } 627 1.10 cgd } 628 1.10 cgd 629 1.10 cgd int 630 1.52 xtraeme extractfile(char *name) 631 1.10 cgd { 632 1.64 dholland char dbuffer[DIGEST_BUFFER_SIZE]; 633 1.71 christos u_int flags; 634 1.30 enami uid_t uid; 635 1.30 enami gid_t gid; 636 1.14 mycroft mode_t mode; 637 1.71 christos int extsize; 638 1.68 enami struct timespec mtimep[2], ctimep[2]; 639 1.10 cgd struct entry *ep; 640 1.48 fvdl int setbirth; 641 1.71 christos char *buf; 642 1.10 cgd 643 1.10 cgd curfile.name = name; 644 1.10 cgd curfile.action = USING; 645 1.48 fvdl mtimep[0].tv_sec = curfile.atime_sec; 646 1.68 enami mtimep[0].tv_nsec = curfile.atime_nsec; 647 1.48 fvdl mtimep[1].tv_sec = curfile.mtime_sec; 648 1.68 enami mtimep[1].tv_nsec = curfile.mtime_nsec; 649 1.48 fvdl 650 1.48 fvdl setbirth = curfile.birthtime_sec != 0; 651 1.48 fvdl 652 1.48 fvdl if (setbirth) { 653 1.48 fvdl ctimep[0].tv_sec = curfile.atime_sec; 654 1.68 enami ctimep[0].tv_nsec = curfile.atime_nsec; 655 1.48 fvdl ctimep[1].tv_sec = curfile.birthtime_sec; 656 1.68 enami ctimep[1].tv_nsec = curfile.birthtime_nsec; 657 1.48 fvdl } 658 1.71 christos extsize = curfile.extsize; 659 1.73 chs uid = getuid(); 660 1.73 chs if (uid == 0) 661 1.73 chs uid = curfile.uid; 662 1.48 fvdl gid = curfile.gid; 663 1.48 fvdl mode = curfile.mode; 664 1.48 fvdl flags = curfile.file_flags; 665 1.10 cgd switch (mode & IFMT) { 666 1.10 cgd 667 1.10 cgd default: 668 1.10 cgd fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); 669 1.10 cgd skipfile(); 670 1.10 cgd return (FAIL); 671 1.10 cgd 672 1.10 cgd case IFSOCK: 673 1.10 cgd vprintf(stdout, "skipped socket %s\n", name); 674 1.10 cgd skipfile(); 675 1.10 cgd return (GOOD); 676 1.10 cgd 677 1.10 cgd case IFDIR: 678 1.10 cgd if (mflag) { 679 1.10 cgd ep = lookupname(name); 680 1.10 cgd if (ep == NULL || ep->e_flags & EXTRACT) 681 1.10 cgd panic("unextracted directory %s\n", name); 682 1.10 cgd skipfile(); 683 1.10 cgd return (GOOD); 684 1.10 cgd } 685 1.10 cgd vprintf(stdout, "extract file %s\n", name); 686 1.10 cgd return (genliteraldir(name, curfile.ino)); 687 1.10 cgd 688 1.10 cgd case IFLNK: 689 1.10 cgd lnkbuf[0] = '\0'; 690 1.10 cgd pathlen = 0; 691 1.71 christos buf = setupextattr(extsize); 692 1.71 christos getfile(xtrlnkfile, xtrattr, xtrlnkskip); 693 1.10 cgd if (pathlen == 0) { 694 1.10 cgd vprintf(stdout, 695 1.10 cgd "%s: zero length symbolic link (ignored)\n", name); 696 1.10 cgd return (GOOD); 697 1.10 cgd } 698 1.37 christos if (uflag) 699 1.37 christos (void) unlink(name); 700 1.30 enami if (linkit(lnkbuf, name, SYMLINK) == GOOD) { 701 1.48 fvdl if (setbirth) 702 1.68 enami (void) lutimens(name, ctimep); 703 1.68 enami (void) lutimens(name, mtimep); 704 1.31 mycroft (void) lchown(name, uid, gid); 705 1.31 mycroft (void) lchmod(name, mode); 706 1.74 chs if (extsize > 0) 707 1.74 chs set_extattr(-1, name, buf, extsize, SXA_LINK); 708 1.51 bouyer if (Mtreefile) { 709 1.51 bouyer writemtree(name, "link", 710 1.51 bouyer uid, gid, mode, flags); 711 1.51 bouyer } else 712 1.51 bouyer (void) lchflags(name, flags); 713 1.30 enami return (GOOD); 714 1.30 enami } 715 1.30 enami return (FAIL); 716 1.12 mycroft 717 1.14 mycroft case IFCHR: 718 1.14 mycroft case IFBLK: 719 1.14 mycroft vprintf(stdout, "extract special file %s\n", name); 720 1.12 mycroft if (Nflag) { 721 1.12 mycroft skipfile(); 722 1.12 mycroft return (GOOD); 723 1.12 mycroft } 724 1.37 christos if (uflag) 725 1.37 christos (void) unlink(name); 726 1.34 enami if (mknod(name, (mode & (IFCHR | IFBLK)) | 0600, 727 1.48 fvdl (int)curfile.rdev) < 0) { 728 1.14 mycroft fprintf(stderr, "%s: cannot create special file: %s\n", 729 1.12 mycroft name, strerror(errno)); 730 1.12 mycroft skipfile(); 731 1.12 mycroft return (FAIL); 732 1.12 mycroft } 733 1.74 chs (void) chown(name, uid, gid); 734 1.74 chs (void) chmod(name, mode); 735 1.71 christos if (extsize == 0) { 736 1.71 christos skipfile(); 737 1.71 christos } else { 738 1.71 christos buf = setupextattr(extsize); 739 1.71 christos getfile(xtrnull, xtrattr, xtrnull); 740 1.71 christos set_extattr(-1, name, buf, extsize, SXA_FILE); 741 1.71 christos } 742 1.48 fvdl if (setbirth) 743 1.68 enami (void) utimens(name, ctimep); 744 1.68 enami (void) utimens(name, mtimep); 745 1.51 bouyer if (Mtreefile) { 746 1.51 bouyer writemtree(name, 747 1.51 bouyer ((mode & (S_IFBLK | IFCHR)) == IFBLK) ? 748 1.51 bouyer "block" : "char", 749 1.51 bouyer uid, gid, mode, flags); 750 1.51 bouyer } else 751 1.51 bouyer (void) chflags(name, flags); 752 1.12 mycroft return (GOOD); 753 1.10 cgd 754 1.14 mycroft case IFIFO: 755 1.14 mycroft vprintf(stdout, "extract fifo %s\n", name); 756 1.10 cgd if (Nflag) { 757 1.10 cgd skipfile(); 758 1.10 cgd return (GOOD); 759 1.10 cgd } 760 1.37 christos if (uflag) 761 1.37 christos (void) unlink(name); 762 1.33 enami if (mkfifo(name, 0600) < 0) { 763 1.14 mycroft fprintf(stderr, "%s: cannot create fifo: %s\n", 764 1.10 cgd name, strerror(errno)); 765 1.10 cgd skipfile(); 766 1.10 cgd return (FAIL); 767 1.10 cgd } 768 1.74 chs (void) chown(name, uid, gid); 769 1.74 chs (void) chmod(name, mode); 770 1.71 christos if (extsize == 0) { 771 1.71 christos skipfile(); 772 1.71 christos } else { 773 1.71 christos buf = setupextattr(extsize); 774 1.71 christos getfile(xtrnull, xtrattr, xtrnull); 775 1.71 christos set_extattr(-1, name, buf, extsize, SXA_FILE); 776 1.71 christos } 777 1.48 fvdl if (setbirth) 778 1.68 enami (void) utimens(name, ctimep); 779 1.68 enami (void) utimens(name, mtimep); 780 1.51 bouyer if (Mtreefile) { 781 1.51 bouyer writemtree(name, "fifo", 782 1.51 bouyer uid, gid, mode, flags); 783 1.51 bouyer } else 784 1.51 bouyer (void) chflags(name, flags); 785 1.10 cgd return (GOOD); 786 1.10 cgd 787 1.10 cgd case IFREG: 788 1.10 cgd vprintf(stdout, "extract file %s\n", name); 789 1.37 christos if (uflag) 790 1.37 christos (void) unlink(name); 791 1.50 enami if (!Nflag && (ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 792 1.32 enami 0600)) < 0) { 793 1.10 cgd fprintf(stderr, "%s: cannot create file: %s\n", 794 1.10 cgd name, strerror(errno)); 795 1.10 cgd skipfile(); 796 1.10 cgd return (FAIL); 797 1.10 cgd } 798 1.50 enami if (Dflag) 799 1.50 enami (*ddesc->dd_init)(&dcontext); 800 1.74 chs (void) fchown(ofile, uid, gid); 801 1.74 chs (void) fchmod(ofile, mode); 802 1.71 christos buf = setupextattr(extsize); 803 1.71 christos getfile(xtrfile, xtrattr, xtrskip); 804 1.71 christos if (extsize > 0) 805 1.71 christos set_extattr(ofile, name, buf, extsize, SXA_FD); 806 1.50 enami if (Dflag) { 807 1.64 dholland (*ddesc->dd_end)(&dcontext, dbuffer); 808 1.50 enami for (ep = lookupname(name); ep != NULL; 809 1.50 enami ep = ep->e_links) 810 1.50 enami fprintf(stdout, "%s (%s) = %s\n", 811 1.50 enami ddesc->dd_name, myname(ep), 812 1.64 dholland dbuffer); 813 1.50 enami } 814 1.50 enami if (Nflag) 815 1.50 enami return (GOOD); 816 1.48 fvdl if (setbirth) 817 1.68 enami (void) futimens(ofile, ctimep); 818 1.68 enami (void) futimens(ofile, mtimep); 819 1.51 bouyer if (Mtreefile) { 820 1.51 bouyer writemtree(name, "file", 821 1.51 bouyer uid, gid, mode, flags); 822 1.51 bouyer } else 823 1.51 bouyer (void) fchflags(ofile, flags); 824 1.10 cgd (void) close(ofile); 825 1.10 cgd return (GOOD); 826 1.10 cgd } 827 1.10 cgd /* NOTREACHED */ 828 1.10 cgd } 829 1.10 cgd 830 1.10 cgd /* 831 1.71 christos * Set attributes on a file descriptor, link, or file. 832 1.71 christos */ 833 1.71 christos void 834 1.71 christos set_extattr(int fd, char *name, void *buf, int size, enum set_extattr_mode mode) 835 1.71 christos { 836 1.71 christos struct extattr *eap, *eaend; 837 1.71 christos const char *method; 838 1.71 christos ssize_t res; 839 1.71 christos int error; 840 1.71 christos char eaname[EXTATTR_MAXNAMELEN + 1]; 841 1.71 christos 842 1.71 christos vprintf(stdout, "Set attributes for %s:", name); 843 1.71 christos eaend = (void *)((char *)buf + size); 844 1.71 christos for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) { 845 1.71 christos /* 846 1.71 christos * Make sure this entry is complete. 847 1.71 christos */ 848 1.71 christos if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) { 849 1.71 christos dprintf(stdout, "\n\t%scorrupted", 850 1.71 christos eap == buf ? "" : "remainder "); 851 1.71 christos break; 852 1.71 christos } 853 1.71 christos if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY) 854 1.71 christos continue; 855 1.71 christos snprintf(eaname, sizeof(eaname), "%.*s", 856 1.71 christos (int)eap->ea_namelength, eap->ea_name); 857 1.71 christos vprintf(stdout, "\n\t%s, (%d bytes), %s", 858 1.71 christos namespace_names[eap->ea_namespace], eap->ea_length, 859 1.71 christos eaname); 860 1.71 christos /* 861 1.71 christos * First we try the general attribute setting interface. 862 1.71 christos * However, some attributes can only be set by root or 863 1.71 christos * by using special interfaces (for example, ACLs). 864 1.71 christos */ 865 1.71 christos switch (mode) { 866 1.71 christos case SXA_FD: 867 1.71 christos res = extattr_set_fd(fd, eap->ea_namespace, 868 1.71 christos eaname, EXTATTR_CONTENT(eap), 869 1.71 christos EXTATTR_CONTENT_SIZE(eap)); 870 1.71 christos method = "extattr_set_fd"; 871 1.71 christos break; 872 1.71 christos case SXA_LINK: 873 1.71 christos res = extattr_set_link(name, eap->ea_namespace, 874 1.71 christos eaname, EXTATTR_CONTENT(eap), 875 1.71 christos EXTATTR_CONTENT_SIZE(eap)); 876 1.71 christos method = "extattr_set_link"; 877 1.71 christos break; 878 1.71 christos case SXA_FILE: 879 1.71 christos res = extattr_set_file(name, eap->ea_namespace, 880 1.71 christos eaname, EXTATTR_CONTENT(eap), 881 1.71 christos EXTATTR_CONTENT_SIZE(eap)); 882 1.71 christos method = "extattr_set_file"; 883 1.71 christos break; 884 1.71 christos default: 885 1.71 christos abort(); 886 1.71 christos } 887 1.71 christos if (res != -1) { 888 1.71 christos dprintf(stdout, " (set using %s)", method); 889 1.71 christos continue; 890 1.71 christos } 891 1.71 christos /* 892 1.71 christos * If the general interface refuses to set the attribute, 893 1.71 christos * then we try all the specialized interfaces that we 894 1.71 christos * know about. 895 1.71 christos */ 896 1.71 christos if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 897 1.71 christos strcmp(eaname, POSIX1E_ACL_ACCESS_EXTATTR_NAME) == 0) { 898 1.71 christos switch (mode) { 899 1.71 christos case SXA_FD: 900 1.71 christos error = acl_set_fd(fd, EXTATTR_CONTENT(eap)); 901 1.71 christos method = "acl_set_fd"; 902 1.71 christos break; 903 1.71 christos case SXA_LINK: 904 1.71 christos error = acl_set_link_np(name, ACL_TYPE_ACCESS, 905 1.71 christos EXTATTR_CONTENT(eap)); 906 1.71 christos method = "acl_set_link_np"; 907 1.71 christos break; 908 1.71 christos case SXA_FILE: 909 1.71 christos error = acl_set_file(name, ACL_TYPE_ACCESS, 910 1.71 christos EXTATTR_CONTENT(eap)); 911 1.71 christos method = "acl_set_file"; 912 1.71 christos break; 913 1.71 christos default: 914 1.71 christos abort(); 915 1.71 christos } 916 1.71 christos if (error != -1) { 917 1.71 christos dprintf(stdout, " (set using %s)", method); 918 1.71 christos continue; 919 1.71 christos } 920 1.71 christos } 921 1.71 christos if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 922 1.71 christos strcmp(eaname, POSIX1E_ACL_DEFAULT_EXTATTR_NAME) == 0) { 923 1.71 christos switch (mode) { 924 1.71 christos case SXA_FD: 925 1.71 christos error = acl_set_fd(fd, EXTATTR_CONTENT(eap)); 926 1.71 christos method = "acl_set_fd"; 927 1.71 christos break; 928 1.71 christos case SXA_LINK: 929 1.71 christos error = acl_set_link_np(name, ACL_TYPE_DEFAULT, 930 1.71 christos EXTATTR_CONTENT(eap)); 931 1.71 christos method = "acl_set_link_np"; 932 1.71 christos break; 933 1.71 christos case SXA_FILE: 934 1.71 christos error = acl_set_file(name, ACL_TYPE_DEFAULT, 935 1.71 christos EXTATTR_CONTENT(eap)); 936 1.71 christos method = "acl_set_file"; 937 1.71 christos break; 938 1.71 christos default: 939 1.71 christos abort(); 940 1.71 christos } 941 1.71 christos if (error != -1) { 942 1.71 christos dprintf(stdout, " (set using %s)", method); 943 1.71 christos continue; 944 1.71 christos } 945 1.71 christos } 946 1.71 christos vprintf(stdout, " (unable to set)"); 947 1.71 christos } 948 1.71 christos vprintf(stdout, "\n"); 949 1.71 christos } 950 1.71 christos 951 1.71 christos /* 952 1.10 cgd * skip over bit maps on the tape 953 1.10 cgd */ 954 1.10 cgd void 955 1.52 xtraeme skipmaps(void) 956 1.10 cgd { 957 1.10 cgd 958 1.10 cgd while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI) 959 1.10 cgd skipfile(); 960 1.10 cgd } 961 1.10 cgd 962 1.10 cgd /* 963 1.10 cgd * skip over a file on the tape 964 1.10 cgd */ 965 1.10 cgd void 966 1.52 xtraeme skipfile(void) 967 1.10 cgd { 968 1.10 cgd 969 1.10 cgd curfile.action = SKIP; 970 1.71 christos getfile(xtrnull, xtrnull, xtrnull); 971 1.71 christos } 972 1.71 christos 973 1.71 christos /* 974 1.71 christos * Skip a hole in an output file 975 1.71 christos */ 976 1.71 christos static void 977 1.71 christos skiphole(void (*skip)(char *, size_t), volatile size_t *seekpos) 978 1.71 christos { 979 1.71 christos char buf[MAXBSIZE]; 980 1.71 christos size_t s = *seekpos; 981 1.71 christos 982 1.71 christos if (s > 0) { 983 1.71 christos (*skip)(buf, s); 984 1.71 christos *seekpos = 0; 985 1.71 christos } 986 1.10 cgd } 987 1.10 cgd 988 1.10 cgd /* 989 1.59 hannken * Extract a bitmap from the tape. 990 1.59 hannken * The first bitmap sets maxino; 991 1.59 hannken * other bitmaps must be of same size. 992 1.59 hannken */ 993 1.59 hannken void 994 1.59 hannken getbitmap(char **map) 995 1.59 hannken { 996 1.59 hannken int i; 997 1.59 hannken size_t volatile size = spcl.c_size; 998 1.59 hannken size_t volatile mapsize = size; 999 1.59 hannken char *mapptr; 1000 1.59 hannken 1001 1.59 hannken curfile.action = USING; 1002 1.59 hannken if (spcl.c_type == TS_END) 1003 1.59 hannken panic("ran off end of tape\n"); 1004 1.59 hannken if (spcl.c_magic != FS_UFS2_MAGIC) 1005 1.59 hannken panic("not at beginning of a file\n"); 1006 1.59 hannken if (!gettingfile && setjmp(restart) != 0) 1007 1.59 hannken return; 1008 1.59 hannken gettingfile++; 1009 1.59 hannken mapptr = *map = malloc(size); 1010 1.59 hannken loop: 1011 1.59 hannken if (*map == NULL) 1012 1.59 hannken panic("no memory for %s\n", curfile.name); 1013 1.59 hannken for (i = 0; i < spcl.c_count && size >= TP_BSIZE; i++) { 1014 1.59 hannken readtape(mapptr); 1015 1.59 hannken mapptr += TP_BSIZE; 1016 1.59 hannken size -= TP_BSIZE; 1017 1.59 hannken } 1018 1.59 hannken if (size != 0 || i != spcl.c_count) 1019 1.59 hannken panic("%s: inconsistent map size\n", curfile.name); 1020 1.59 hannken if (gethead(&spcl) == GOOD && spcl.c_type == TS_ADDR) { 1021 1.59 hannken size = spcl.c_count * TP_BSIZE; 1022 1.59 hannken *map = realloc(*map, mapsize + size); 1023 1.59 hannken mapptr = *map + mapsize; 1024 1.59 hannken mapsize += size; 1025 1.59 hannken goto loop; 1026 1.59 hannken } 1027 1.59 hannken if (maxino == 0) 1028 1.59 hannken maxino = mapsize * NBBY + 1; 1029 1.59 hannken else if (maxino != mapsize * NBBY + 1) 1030 1.59 hannken panic("%s: map size changed\n", curfile.name); 1031 1.59 hannken findinode(&spcl); 1032 1.59 hannken gettingfile = 0; 1033 1.59 hannken } 1034 1.59 hannken 1035 1.59 hannken /* 1036 1.10 cgd * Extract a file from the tape. 1037 1.10 cgd * When an allocated block is found it is passed to the fill function; 1038 1.10 cgd * when an unallocated block (hole) is found, a zeroed buffer is passed 1039 1.10 cgd * to the skip function. 1040 1.10 cgd */ 1041 1.10 cgd void 1042 1.71 christos getfile(void (*datafill)(char *, size_t), void (*attrfill)(char *, size_t), 1043 1.71 christos void (*skip)(char *, size_t)) 1044 1.10 cgd { 1045 1.25 lukem int i; 1046 1.71 christos volatile off_t size; 1047 1.71 christos volatile size_t seekpos; 1048 1.71 christos volatile int curblk, attrsize; 1049 1.71 christos void (*fillit)(char *, size_t); 1050 1.10 cgd char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; 1051 1.10 cgd char junk[TP_BSIZE]; 1052 1.10 cgd 1053 1.58 christos curblk = 0; 1054 1.58 christos size = spcl.c_size; 1055 1.71 christos seekpos = 0; 1056 1.71 christos attrsize = spcl.c_extsize; 1057 1.28 lukem 1058 1.10 cgd if (spcl.c_type == TS_END) 1059 1.10 cgd panic("ran off end of tape\n"); 1060 1.48 fvdl if (spcl.c_magic != FS_UFS2_MAGIC) 1061 1.10 cgd panic("not at beginning of a file\n"); 1062 1.10 cgd if (!gettingfile && setjmp(restart) != 0) 1063 1.10 cgd return; 1064 1.10 cgd gettingfile++; 1065 1.71 christos fillit = datafill; 1066 1.71 christos if (size == 0 && attrsize > 0) { 1067 1.71 christos fillit = attrfill; 1068 1.71 christos size = attrsize; 1069 1.71 christos attrsize = 0; 1070 1.71 christos } 1071 1.10 cgd loop: 1072 1.10 cgd for (i = 0; i < spcl.c_count; i++) { 1073 1.59 hannken if (spcl.c_addr[i]) { 1074 1.10 cgd readtape(&buf[curblk++][0]); 1075 1.63 lukem if ((uint32_t)curblk == fssize / TP_BSIZE) { 1076 1.71 christos skiphole(skip, &seekpos); 1077 1.71 christos (*fillit)((char *)buf, (long)(size > TP_BSIZE ? 1078 1.29 lukem fssize : (curblk - 1) * TP_BSIZE + size)); 1079 1.10 cgd curblk = 0; 1080 1.10 cgd } 1081 1.10 cgd } else { 1082 1.10 cgd if (curblk > 0) { 1083 1.71 christos skiphole(skip, &seekpos); 1084 1.71 christos (*fillit)((char *)buf, (long)(size > TP_BSIZE ? 1085 1.29 lukem curblk * TP_BSIZE : 1086 1.29 lukem (curblk - 1) * TP_BSIZE + size)); 1087 1.10 cgd curblk = 0; 1088 1.10 cgd } 1089 1.71 christos /* 1090 1.71 christos * We have a block of a hole. Don't skip it 1091 1.71 christos * now, because there may be next adjacent 1092 1.71 christos * block of the hole in the file. Postpone the 1093 1.71 christos * seek until next file write. 1094 1.71 christos */ 1095 1.71 christos seekpos += (long)MIN(TP_BSIZE, size); 1096 1.10 cgd } 1097 1.10 cgd if ((size -= TP_BSIZE) <= 0) { 1098 1.71 christos if (size > -TP_BSIZE && curblk > 0) { 1099 1.71 christos skiphole(skip, &seekpos); 1100 1.71 christos (*fillit)((char *)buf, 1101 1.71 christos (long)((curblk * TP_BSIZE) + size)); 1102 1.71 christos curblk = 0; 1103 1.71 christos } 1104 1.71 christos if (attrsize > 0) { 1105 1.71 christos fillit = attrfill; 1106 1.71 christos size = attrsize; 1107 1.71 christos attrsize = 0; 1108 1.71 christos continue; 1109 1.71 christos } 1110 1.71 christos if (spcl.c_count - i > 1) 1111 1.71 christos dprintf(stdout, "skipping %d junk block(s)\n", 1112 1.71 christos spcl.c_count - i - 1); 1113 1.59 hannken for (i++; i < spcl.c_count; i++) 1114 1.59 hannken if (spcl.c_addr[i]) 1115 1.59 hannken readtape(junk); 1116 1.10 cgd break; 1117 1.10 cgd } 1118 1.10 cgd } 1119 1.10 cgd if (gethead(&spcl) == GOOD && size > 0) { 1120 1.10 cgd if (spcl.c_type == TS_ADDR) 1121 1.10 cgd goto loop; 1122 1.10 cgd dprintf(stdout, 1123 1.10 cgd "Missing address (header) block for %s at %d blocks\n", 1124 1.10 cgd curfile.name, blksread); 1125 1.10 cgd } 1126 1.10 cgd if (curblk > 0) 1127 1.72 mrg panic("getfile: lost data: %s\n", curfile.name); 1128 1.61 hannken /* Skip over Linux extended attributes. */ 1129 1.61 hannken if (spcl.c_type == TS_INODE && (spcl.c_flags & DR_EXTATTRIBUTES)) { 1130 1.61 hannken for (i = 0; i < spcl.c_count; i++) 1131 1.61 hannken readtape(junk); 1132 1.61 hannken (void)gethead(&spcl); 1133 1.61 hannken } 1134 1.10 cgd findinode(&spcl); 1135 1.10 cgd gettingfile = 0; 1136 1.10 cgd } 1137 1.10 cgd 1138 1.10 cgd /* 1139 1.71 christos * These variables are shared between the next two functions. 1140 1.71 christos */ 1141 1.71 christos static size_t extbufsize = 0; 1142 1.71 christos static char *extbuf; 1143 1.71 christos static size_t extloc; 1144 1.71 christos 1145 1.71 christos /* 1146 1.71 christos * Allocate a buffer into which to extract extended attributes. 1147 1.71 christos */ 1148 1.71 christos static char * 1149 1.71 christos setupextattr(size_t extsize) 1150 1.71 christos { 1151 1.71 christos 1152 1.71 christos extloc = 0; 1153 1.71 christos if (extsize <= extbufsize) 1154 1.71 christos return (extbuf); 1155 1.71 christos if (extbufsize > 0) 1156 1.71 christos free(extbuf); 1157 1.71 christos if ((extbuf = malloc(extsize)) != NULL) { 1158 1.71 christos extbufsize = extsize; 1159 1.71 christos return (extbuf); 1160 1.71 christos } 1161 1.71 christos extbufsize = 0; 1162 1.71 christos extbuf = NULL; 1163 1.71 christos fprintf(stderr, "Cannot extract %zu bytes %s for inode %ju, name %s\n", 1164 1.71 christos extsize, "of extended attributes", (uintmax_t)curfile.ino, 1165 1.71 christos curfile.name); 1166 1.71 christos return (NULL); 1167 1.71 christos } 1168 1.71 christos 1169 1.71 christos /* 1170 1.71 christos * Extract the next block of extended attributes. 1171 1.71 christos */ 1172 1.71 christos static void 1173 1.71 christos xtrattr(char *buf, size_t size) 1174 1.71 christos { 1175 1.71 christos 1176 1.71 christos if (extloc + size > extbufsize) 1177 1.71 christos panic("overrun attribute buffer\n"); 1178 1.71 christos memmove(&extbuf[extloc], buf, size); 1179 1.71 christos extloc += size; 1180 1.71 christos } 1181 1.71 christos 1182 1.71 christos /* 1183 1.10 cgd * Write out the next block of a file. 1184 1.10 cgd */ 1185 1.10 cgd static void 1186 1.71 christos xtrfile(char *buf, size_t size) 1187 1.10 cgd { 1188 1.10 cgd 1189 1.50 enami if (Dflag) 1190 1.50 enami (*ddesc->dd_update)(&dcontext, buf, size); 1191 1.10 cgd if (Nflag) 1192 1.10 cgd return; 1193 1.10 cgd if (write(ofile, buf, (int) size) == -1) { 1194 1.10 cgd fprintf(stderr, 1195 1.71 christos "write error extracting inode %ju, name %s\nwrite: %s\n", 1196 1.71 christos (uintmax_t)curfile.ino, curfile.name, 1197 1.54 christos strerror(errno)); 1198 1.15 mycroft exit(1); 1199 1.10 cgd } 1200 1.10 cgd } 1201 1.10 cgd 1202 1.10 cgd /* 1203 1.10 cgd * Skip over a hole in a file. 1204 1.10 cgd */ 1205 1.10 cgd /* ARGSUSED */ 1206 1.10 cgd static void 1207 1.71 christos xtrskip(char *buf, size_t size) 1208 1.10 cgd { 1209 1.10 cgd 1210 1.50 enami if (Dflag) 1211 1.50 enami (*ddesc->dd_update)(&dcontext, buf, size); 1212 1.50 enami if (Nflag) 1213 1.50 enami return; 1214 1.10 cgd if (lseek(ofile, size, SEEK_CUR) == -1) { 1215 1.10 cgd fprintf(stderr, 1216 1.71 christos "seek error extracting inode %ju, name %s\nlseek: %s\n", 1217 1.71 christos (uintmax_t)curfile.ino, curfile.name, 1218 1.54 christos strerror(errno)); 1219 1.15 mycroft exit(1); 1220 1.10 cgd } 1221 1.10 cgd } 1222 1.10 cgd 1223 1.10 cgd /* 1224 1.10 cgd * Collect the next block of a symbolic link. 1225 1.10 cgd */ 1226 1.10 cgd static void 1227 1.71 christos xtrlnkfile(char *buf, size_t size) 1228 1.10 cgd { 1229 1.10 cgd 1230 1.10 cgd pathlen += size; 1231 1.10 cgd if (pathlen > MAXPATHLEN) { 1232 1.10 cgd fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n", 1233 1.10 cgd curfile.name, lnkbuf, buf, pathlen); 1234 1.15 mycroft exit(1); 1235 1.10 cgd } 1236 1.10 cgd (void) strcat(lnkbuf, buf); 1237 1.10 cgd } 1238 1.10 cgd 1239 1.10 cgd /* 1240 1.10 cgd * Skip over a hole in a symbolic link (should never happen). 1241 1.10 cgd */ 1242 1.10 cgd /* ARGSUSED */ 1243 1.10 cgd static void 1244 1.71 christos xtrlnkskip(char *buf __unused, size_t size __unused) 1245 1.10 cgd { 1246 1.10 cgd 1247 1.10 cgd fprintf(stderr, "unallocated block in symbolic link %s\n", 1248 1.10 cgd curfile.name); 1249 1.15 mycroft exit(1); 1250 1.10 cgd } 1251 1.10 cgd 1252 1.10 cgd /* 1253 1.10 cgd * Noop, when an extraction function is not needed. 1254 1.10 cgd */ 1255 1.10 cgd /* ARGSUSED */ 1256 1.10 cgd void 1257 1.71 christos xtrnull(char *buf __unused, size_t size __unused) 1258 1.10 cgd { 1259 1.10 cgd 1260 1.10 cgd return; 1261 1.10 cgd } 1262 1.10 cgd 1263 1.10 cgd /* 1264 1.10 cgd * Read TP_BSIZE blocks from the input. 1265 1.10 cgd * Handle read errors, and end of media. 1266 1.10 cgd */ 1267 1.10 cgd static void 1268 1.52 xtraeme readtape(char *buf) 1269 1.10 cgd { 1270 1.28 lukem int rd, newvol, i; 1271 1.10 cgd int cnt, seek_failed; 1272 1.10 cgd 1273 1.10 cgd if (blkcnt < numtrec) { 1274 1.29 lukem memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); 1275 1.10 cgd blksread++; 1276 1.10 cgd tpblksread++; 1277 1.10 cgd return; 1278 1.10 cgd } 1279 1.10 cgd for (i = 0; i < ntrec; i++) 1280 1.10 cgd ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 1281 1.10 cgd if (numtrec == 0) 1282 1.10 cgd numtrec = ntrec; 1283 1.10 cgd cnt = ntrec * TP_BSIZE; 1284 1.10 cgd rd = 0; 1285 1.10 cgd getmore: 1286 1.10 cgd #ifdef RRESTORE 1287 1.10 cgd if (host) 1288 1.10 cgd i = rmtread(&tapebuf[rd], cnt); 1289 1.10 cgd else 1290 1.10 cgd #endif 1291 1.10 cgd i = read(mt, &tapebuf[rd], cnt); 1292 1.10 cgd /* 1293 1.10 cgd * Check for mid-tape short read error. 1294 1.10 cgd * If found, skip rest of buffer and start with the next. 1295 1.10 cgd */ 1296 1.10 cgd if (!pipein && numtrec < ntrec && i > 0) { 1297 1.10 cgd dprintf(stdout, "mid-media short read error.\n"); 1298 1.10 cgd numtrec = ntrec; 1299 1.10 cgd } 1300 1.10 cgd /* 1301 1.10 cgd * Handle partial block read. 1302 1.10 cgd */ 1303 1.10 cgd if (pipein && i == 0 && rd > 0) 1304 1.10 cgd i = rd; 1305 1.10 cgd else if (i > 0 && i != ntrec * TP_BSIZE) { 1306 1.10 cgd if (pipein) { 1307 1.10 cgd rd += i; 1308 1.10 cgd cnt -= i; 1309 1.10 cgd if (cnt > 0) 1310 1.10 cgd goto getmore; 1311 1.10 cgd i = rd; 1312 1.10 cgd } else { 1313 1.10 cgd /* 1314 1.10 cgd * Short read. Process the blocks read. 1315 1.10 cgd */ 1316 1.10 cgd if (i % TP_BSIZE != 0) 1317 1.10 cgd vprintf(stdout, 1318 1.10 cgd "partial block read: %d should be %d\n", 1319 1.10 cgd i, ntrec * TP_BSIZE); 1320 1.10 cgd numtrec = i / TP_BSIZE; 1321 1.10 cgd } 1322 1.10 cgd } 1323 1.10 cgd /* 1324 1.10 cgd * Handle read error. 1325 1.10 cgd */ 1326 1.10 cgd if (i < 0) { 1327 1.10 cgd fprintf(stderr, "Tape read error while "); 1328 1.10 cgd switch (curfile.action) { 1329 1.10 cgd default: 1330 1.10 cgd fprintf(stderr, "trying to set up tape\n"); 1331 1.10 cgd break; 1332 1.10 cgd case UNKNOWN: 1333 1.10 cgd fprintf(stderr, "trying to resynchronize\n"); 1334 1.10 cgd break; 1335 1.10 cgd case USING: 1336 1.10 cgd fprintf(stderr, "restoring %s\n", curfile.name); 1337 1.10 cgd break; 1338 1.10 cgd case SKIP: 1339 1.71 christos fprintf(stderr, "skipping over inode %ju\n", 1340 1.71 christos (uintmax_t)curfile.ino); 1341 1.10 cgd break; 1342 1.10 cgd } 1343 1.10 cgd if (!yflag && !reply("continue")) 1344 1.15 mycroft exit(1); 1345 1.10 cgd i = ntrec * TP_BSIZE; 1346 1.13 mycroft memset(tapebuf, 0, i); 1347 1.10 cgd #ifdef RRESTORE 1348 1.10 cgd if (host) 1349 1.10 cgd seek_failed = (rmtseek(i, 1) < 0); 1350 1.10 cgd else 1351 1.10 cgd #endif 1352 1.10 cgd seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1); 1353 1.10 cgd 1354 1.10 cgd if (seek_failed) { 1355 1.10 cgd fprintf(stderr, 1356 1.10 cgd "continuation failed: %s\n", strerror(errno)); 1357 1.15 mycroft exit(1); 1358 1.10 cgd } 1359 1.10 cgd } 1360 1.10 cgd /* 1361 1.10 cgd * Handle end of tape. 1362 1.10 cgd */ 1363 1.10 cgd if (i == 0) { 1364 1.10 cgd vprintf(stdout, "End-of-tape encountered\n"); 1365 1.10 cgd if (!pipein) { 1366 1.10 cgd newvol = volno + 1; 1367 1.10 cgd volno = 0; 1368 1.10 cgd numtrec = 0; 1369 1.10 cgd getvol(newvol); 1370 1.10 cgd readtape(buf); 1371 1.10 cgd return; 1372 1.10 cgd } 1373 1.10 cgd if (rd % TP_BSIZE != 0) 1374 1.10 cgd panic("partial block read: %d should be %d\n", 1375 1.10 cgd rd, ntrec * TP_BSIZE); 1376 1.10 cgd terminateinput(); 1377 1.29 lukem memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE); 1378 1.10 cgd } 1379 1.10 cgd blkcnt = 0; 1380 1.29 lukem memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); 1381 1.10 cgd blksread++; 1382 1.10 cgd tpblksread++; 1383 1.10 cgd } 1384 1.10 cgd 1385 1.10 cgd static void 1386 1.52 xtraeme findtapeblksize(void) 1387 1.10 cgd { 1388 1.25 lukem long i; 1389 1.10 cgd 1390 1.10 cgd for (i = 0; i < ntrec; i++) 1391 1.10 cgd ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 1392 1.10 cgd blkcnt = 0; 1393 1.10 cgd #ifdef RRESTORE 1394 1.10 cgd if (host) 1395 1.10 cgd i = rmtread(tapebuf, ntrec * TP_BSIZE); 1396 1.10 cgd else 1397 1.10 cgd #endif 1398 1.10 cgd i = read(mt, tapebuf, ntrec * TP_BSIZE); 1399 1.10 cgd 1400 1.10 cgd if (i <= 0) { 1401 1.10 cgd fprintf(stderr, "tape read error: %s\n", strerror(errno)); 1402 1.15 mycroft exit(1); 1403 1.10 cgd } 1404 1.10 cgd if (i % TP_BSIZE != 0) { 1405 1.28 lukem fprintf(stderr, "Tape block size (%ld) %s (%ld)\n", 1406 1.28 lukem (long)i, "is not a multiple of dump block size", 1407 1.28 lukem (long)TP_BSIZE); 1408 1.15 mycroft exit(1); 1409 1.10 cgd } 1410 1.10 cgd ntrec = i / TP_BSIZE; 1411 1.10 cgd numtrec = ntrec; 1412 1.10 cgd vprintf(stdout, "Tape block size is %d\n", ntrec); 1413 1.10 cgd } 1414 1.10 cgd 1415 1.10 cgd void 1416 1.52 xtraeme closemt(void) 1417 1.10 cgd { 1418 1.10 cgd 1419 1.10 cgd if (mt < 0) 1420 1.10 cgd return; 1421 1.10 cgd #ifdef RRESTORE 1422 1.10 cgd if (host) 1423 1.10 cgd rmtclose(); 1424 1.10 cgd else 1425 1.10 cgd #endif 1426 1.10 cgd (void) close(mt); 1427 1.10 cgd } 1428 1.10 cgd 1429 1.10 cgd /* 1430 1.10 cgd * Read the next block from the tape. 1431 1.10 cgd * Check to see if it is one of several vintage headers. 1432 1.10 cgd * If it is an old style header, convert it to a new style header. 1433 1.10 cgd * If it is not any valid header, return an error. 1434 1.10 cgd */ 1435 1.10 cgd static int 1436 1.52 xtraeme gethead(struct s_spcl *buf) 1437 1.10 cgd { 1438 1.48 fvdl union u_ospcl u_ospcl; 1439 1.10 cgd 1440 1.10 cgd if (!cvtflag) { 1441 1.10 cgd readtape((char *)buf); 1442 1.48 fvdl if (buf->c_magic != NFS_MAGIC && 1443 1.48 fvdl buf->c_magic != FS_UFS2_MAGIC) { 1444 1.48 fvdl if (bswap32(buf->c_magic) != NFS_MAGIC && 1445 1.48 fvdl bswap32(buf->c_magic) != FS_UFS2_MAGIC) 1446 1.10 cgd return (FAIL); 1447 1.10 cgd if (!Bcvt) { 1448 1.10 cgd vprintf(stdout, "Note: Doing Byte swapping\n"); 1449 1.10 cgd Bcvt = 1; 1450 1.10 cgd } 1451 1.10 cgd } 1452 1.10 cgd if (checksum((int *)buf) == FAIL) 1453 1.10 cgd return (FAIL); 1454 1.10 cgd if (Bcvt) 1455 1.48 fvdl swap_header(buf); 1456 1.10 cgd goto good; 1457 1.10 cgd } 1458 1.48 fvdl 1459 1.10 cgd readtape((char *)(&u_ospcl.s_ospcl)); 1460 1.48 fvdl if (checksum((int *)(&u_ospcl.s_ospcl)) == FAIL) 1461 1.48 fvdl return (FAIL); 1462 1.48 fvdl if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC) { 1463 1.48 fvdl if (bswap32(u_ospcl.s_ospcl.c_magic) != OFS_MAGIC) 1464 1.48 fvdl return (FAIL); 1465 1.48 fvdl if (!Bcvt) { 1466 1.48 fvdl vprintf(stdout, "Note: Doing Byte swapping\n"); 1467 1.48 fvdl Bcvt = 1; 1468 1.48 fvdl } 1469 1.48 fvdl swap_old_header(&u_ospcl.s_ospcl); 1470 1.48 fvdl } 1471 1.48 fvdl 1472 1.62 yamt memset(buf, 0, TP_BSIZE); 1473 1.10 cgd buf->c_type = u_ospcl.s_ospcl.c_type; 1474 1.10 cgd buf->c_date = u_ospcl.s_ospcl.c_date; 1475 1.10 cgd buf->c_ddate = u_ospcl.s_ospcl.c_ddate; 1476 1.10 cgd buf->c_volume = u_ospcl.s_ospcl.c_volume; 1477 1.10 cgd buf->c_tapea = u_ospcl.s_ospcl.c_tapea; 1478 1.10 cgd buf->c_inumber = u_ospcl.s_ospcl.c_inumber; 1479 1.10 cgd buf->c_checksum = u_ospcl.s_ospcl.c_checksum; 1480 1.48 fvdl buf->c_mode = u_ospcl.s_ospcl.c_odinode.odi_mode; 1481 1.48 fvdl buf->c_uid = u_ospcl.s_ospcl.c_odinode.odi_uid; 1482 1.48 fvdl buf->c_gid = u_ospcl.s_ospcl.c_odinode.odi_gid; 1483 1.48 fvdl buf->c_size = u_ospcl.s_ospcl.c_odinode.odi_size; 1484 1.48 fvdl buf->c_rdev = u_ospcl.s_ospcl.c_odinode.odi_rdev; 1485 1.48 fvdl buf->c_atime = u_ospcl.s_ospcl.c_odinode.odi_atime; 1486 1.48 fvdl buf->c_mtime = u_ospcl.s_ospcl.c_odinode.odi_mtime; 1487 1.10 cgd buf->c_count = u_ospcl.s_ospcl.c_count; 1488 1.29 lukem memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256); 1489 1.48 fvdl buf->c_magic = FS_UFS2_MAGIC; 1490 1.10 cgd good: 1491 1.10 cgd switch (buf->c_type) { 1492 1.10 cgd 1493 1.10 cgd case TS_CLRI: 1494 1.10 cgd case TS_BITS: 1495 1.10 cgd /* 1496 1.10 cgd * Have to patch up missing information in bit map headers 1497 1.10 cgd */ 1498 1.10 cgd buf->c_inumber = 0; 1499 1.48 fvdl buf->c_size = buf->c_count * TP_BSIZE; 1500 1.10 cgd break; 1501 1.10 cgd 1502 1.10 cgd case TS_TAPE: 1503 1.10 cgd if ((buf->c_flags & DR_NEWINODEFMT) == 0) 1504 1.10 cgd oldinofmt = 1; 1505 1.10 cgd /* fall through */ 1506 1.10 cgd case TS_END: 1507 1.10 cgd buf->c_inumber = 0; 1508 1.10 cgd break; 1509 1.10 cgd 1510 1.10 cgd case TS_INODE: 1511 1.48 fvdl if (buf->c_magic == NFS_MAGIC) { 1512 1.48 fvdl buf->c_tapea = buf->c_old_tapea; 1513 1.48 fvdl buf->c_firstrec = buf->c_old_firstrec; 1514 1.48 fvdl buf->c_date = buf->c_old_date; 1515 1.48 fvdl buf->c_ddate = buf->c_old_ddate; 1516 1.48 fvdl buf->c_atime = buf->c_old_atime; 1517 1.48 fvdl buf->c_mtime = buf->c_old_mtime; 1518 1.48 fvdl buf->c_birthtime = 0; 1519 1.48 fvdl buf->c_birthtimensec = 0; 1520 1.48 fvdl buf->c_atimensec = buf->c_mtimensec = 0; 1521 1.71 christos buf->c_extsize = 0; 1522 1.48 fvdl } 1523 1.48 fvdl 1524 1.10 cgd case TS_ADDR: 1525 1.10 cgd break; 1526 1.10 cgd 1527 1.10 cgd default: 1528 1.10 cgd panic("gethead: unknown inode type %d\n", buf->c_type); 1529 1.10 cgd break; 1530 1.10 cgd } 1531 1.48 fvdl 1532 1.48 fvdl buf->c_magic = FS_UFS2_MAGIC; 1533 1.48 fvdl 1534 1.10 cgd /* 1535 1.10 cgd * If we are restoring a filesystem with old format inodes, 1536 1.10 cgd * copy the uid/gid to the new location. 1537 1.10 cgd */ 1538 1.10 cgd if (oldinofmt) { 1539 1.48 fvdl buf->c_uid = buf->c_spare1[1]; 1540 1.48 fvdl buf->c_gid = buf->c_spare1[2]; 1541 1.10 cgd } 1542 1.10 cgd if (dflag) 1543 1.10 cgd accthdr(buf); 1544 1.10 cgd return(GOOD); 1545 1.10 cgd } 1546 1.10 cgd 1547 1.10 cgd /* 1548 1.10 cgd * Check that a header is where it belongs and predict the next header 1549 1.10 cgd */ 1550 1.10 cgd static void 1551 1.52 xtraeme accthdr(struct s_spcl *header) 1552 1.10 cgd { 1553 1.10 cgd static ino_t previno = 0x7fffffff; 1554 1.10 cgd static int prevtype; 1555 1.10 cgd static long predict; 1556 1.10 cgd long blks, i; 1557 1.10 cgd 1558 1.10 cgd if (header->c_type == TS_TAPE) { 1559 1.10 cgd fprintf(stderr, "Volume header (%s inode format) ", 1560 1.10 cgd oldinofmt ? "old" : "new"); 1561 1.10 cgd if (header->c_firstrec) 1562 1.48 fvdl fprintf(stderr, "begins with record %lld", 1563 1.48 fvdl (long long)header->c_firstrec); 1564 1.10 cgd fprintf(stderr, "\n"); 1565 1.10 cgd previno = 0x7fffffff; 1566 1.10 cgd return; 1567 1.10 cgd } 1568 1.10 cgd if (previno == 0x7fffffff) 1569 1.10 cgd goto newcalc; 1570 1.10 cgd switch (prevtype) { 1571 1.10 cgd case TS_BITS: 1572 1.14 mycroft fprintf(stderr, "Dumped inodes map header"); 1573 1.10 cgd break; 1574 1.10 cgd case TS_CLRI: 1575 1.14 mycroft fprintf(stderr, "Used inodes map header"); 1576 1.10 cgd break; 1577 1.10 cgd case TS_INODE: 1578 1.71 christos fprintf(stderr, "File header, ino %ju", 1579 1.71 christos (uintmax_t)previno); 1580 1.10 cgd break; 1581 1.10 cgd case TS_ADDR: 1582 1.71 christos fprintf(stderr, "File continuation header, ino %ju", 1583 1.71 christos (uintmax_t)previno); 1584 1.10 cgd break; 1585 1.10 cgd case TS_END: 1586 1.10 cgd fprintf(stderr, "End of tape header"); 1587 1.10 cgd break; 1588 1.10 cgd } 1589 1.10 cgd if (predict != blksread - 1) 1590 1.28 lukem fprintf(stderr, "; predicted %ld blocks, got %ld blocks", 1591 1.28 lukem (long)predict, (long)(blksread - 1)); 1592 1.10 cgd fprintf(stderr, "\n"); 1593 1.10 cgd newcalc: 1594 1.10 cgd blks = 0; 1595 1.40 enami switch (header->c_type) { 1596 1.40 enami case TS_END: 1597 1.40 enami break; 1598 1.40 enami case TS_CLRI: 1599 1.40 enami case TS_BITS: 1600 1.40 enami blks = header->c_count; 1601 1.40 enami break; 1602 1.40 enami default: 1603 1.10 cgd for (i = 0; i < header->c_count; i++) 1604 1.10 cgd if (header->c_addr[i] != 0) 1605 1.10 cgd blks++; 1606 1.40 enami break; 1607 1.40 enami } 1608 1.10 cgd predict = blks; 1609 1.10 cgd blksread = 0; 1610 1.10 cgd prevtype = header->c_type; 1611 1.10 cgd previno = header->c_inumber; 1612 1.10 cgd } 1613 1.10 cgd 1614 1.10 cgd /* 1615 1.10 cgd * Find an inode header. 1616 1.10 cgd * Complain if had to skip, and complain is set. 1617 1.10 cgd */ 1618 1.10 cgd static void 1619 1.52 xtraeme findinode(struct s_spcl *header) 1620 1.10 cgd { 1621 1.10 cgd static long skipcnt = 0; 1622 1.10 cgd long i; 1623 1.10 cgd char buf[TP_BSIZE]; 1624 1.10 cgd 1625 1.10 cgd curfile.name = "<name unknown>"; 1626 1.10 cgd curfile.action = UNKNOWN; 1627 1.48 fvdl curfile.mode = 0; 1628 1.10 cgd curfile.ino = 0; 1629 1.45 perseant top: 1630 1.10 cgd do { 1631 1.48 fvdl if (header->c_magic != FS_UFS2_MAGIC) { 1632 1.69 bouyer skip: 1633 1.10 cgd skipcnt++; 1634 1.10 cgd while (gethead(header) == FAIL || 1635 1.10 cgd header->c_date != dumpdate) 1636 1.10 cgd skipcnt++; 1637 1.10 cgd } 1638 1.10 cgd switch (header->c_type) { 1639 1.10 cgd 1640 1.10 cgd case TS_ADDR: 1641 1.10 cgd /* 1642 1.10 cgd * Skip up to the beginning of the next record 1643 1.10 cgd */ 1644 1.10 cgd for (i = 0; i < header->c_count; i++) 1645 1.10 cgd if (header->c_addr[i]) 1646 1.10 cgd readtape(buf); 1647 1.10 cgd while (gethead(header) == FAIL || 1648 1.10 cgd header->c_date != dumpdate) 1649 1.10 cgd skipcnt++; 1650 1.45 perseant /* We've read a header; don't drop it. */ 1651 1.45 perseant goto top; 1652 1.10 cgd 1653 1.10 cgd case TS_INODE: 1654 1.48 fvdl curfile.mode = header->c_mode; 1655 1.48 fvdl curfile.uid = header->c_uid; 1656 1.48 fvdl curfile.gid = header->c_gid; 1657 1.48 fvdl curfile.file_flags = header->c_file_flags; 1658 1.48 fvdl curfile.rdev = header->c_rdev; 1659 1.48 fvdl curfile.atime_sec = header->c_atime; 1660 1.48 fvdl curfile.atime_nsec = header->c_atimensec; 1661 1.48 fvdl curfile.mtime_sec = header->c_mtime; 1662 1.48 fvdl curfile.mtime_nsec = header->c_mtimensec; 1663 1.48 fvdl curfile.birthtime_sec = header->c_birthtime; 1664 1.48 fvdl curfile.birthtime_nsec = header->c_birthtimensec; 1665 1.71 christos curfile.extsize = header->c_extsize; 1666 1.48 fvdl curfile.size = header->c_size; 1667 1.10 cgd curfile.ino = header->c_inumber; 1668 1.10 cgd break; 1669 1.10 cgd 1670 1.10 cgd case TS_END: 1671 1.10 cgd curfile.ino = maxino; 1672 1.10 cgd break; 1673 1.10 cgd 1674 1.10 cgd case TS_CLRI: 1675 1.10 cgd curfile.name = "<file removal list>"; 1676 1.10 cgd break; 1677 1.10 cgd 1678 1.10 cgd case TS_BITS: 1679 1.10 cgd curfile.name = "<file dump list>"; 1680 1.10 cgd break; 1681 1.10 cgd 1682 1.10 cgd case TS_TAPE: 1683 1.10 cgd panic("unexpected tape header\n"); 1684 1.43 enami break; 1685 1.10 cgd 1686 1.10 cgd default: 1687 1.10 cgd panic("unknown tape header type %d\n", spcl.c_type); 1688 1.70 msaitoh fprintf(stderr, "skipping to next header\n"); 1689 1.69 bouyer goto skip; 1690 1.10 cgd 1691 1.10 cgd } 1692 1.10 cgd } while (header->c_type == TS_ADDR); 1693 1.10 cgd if (skipcnt > 0) 1694 1.28 lukem fprintf(stderr, "resync restore, skipped %ld blocks\n", 1695 1.28 lukem (long)skipcnt); 1696 1.10 cgd skipcnt = 0; 1697 1.10 cgd } 1698 1.10 cgd 1699 1.10 cgd static int 1700 1.52 xtraeme checksum(int *buf) 1701 1.10 cgd { 1702 1.25 lukem int i, j; 1703 1.10 cgd 1704 1.10 cgd j = sizeof(union u_spcl) / sizeof(int); 1705 1.10 cgd i = 0; 1706 1.10 cgd if(!Bcvt) { 1707 1.10 cgd do 1708 1.10 cgd i += *buf++; 1709 1.10 cgd while (--j); 1710 1.10 cgd } else { 1711 1.10 cgd do 1712 1.48 fvdl i += bswap32(*buf++); 1713 1.10 cgd while (--j); 1714 1.10 cgd } 1715 1.10 cgd 1716 1.10 cgd if (i != CHECKSUM) { 1717 1.71 christos fprintf(stderr, "Checksum error %o, inode %ju file %s\n", i, 1718 1.71 christos (uintmax_t)curfile.ino, curfile.name); 1719 1.10 cgd return(FAIL); 1720 1.10 cgd } 1721 1.10 cgd return(GOOD); 1722 1.10 cgd } 1723 1.10 cgd 1724 1.10 cgd #ifdef RRESTORE 1725 1.10 cgd #include <stdarg.h> 1726 1.10 cgd 1727 1.10 cgd void 1728 1.10 cgd msg(const char *fmt, ...) 1729 1.10 cgd { 1730 1.10 cgd va_list ap; 1731 1.46 wiz 1732 1.10 cgd va_start(ap, fmt); 1733 1.10 cgd (void)vfprintf(stderr, fmt, ap); 1734 1.10 cgd va_end(ap); 1735 1.10 cgd } 1736 1.10 cgd #endif /* RRESTORE */ 1737 1.10 cgd 1738 1.48 fvdl static void 1739 1.48 fvdl swap_header(struct s_spcl *s) 1740 1.10 cgd { 1741 1.48 fvdl s->c_type = bswap32(s->c_type); 1742 1.48 fvdl s->c_old_date = bswap32(s->c_old_date); 1743 1.48 fvdl s->c_old_ddate = bswap32(s->c_old_ddate); 1744 1.48 fvdl s->c_volume = bswap32(s->c_volume); 1745 1.48 fvdl s->c_old_tapea = bswap32(s->c_old_tapea); 1746 1.48 fvdl s->c_inumber = bswap32(s->c_inumber); 1747 1.48 fvdl s->c_magic = bswap32(s->c_magic); 1748 1.48 fvdl s->c_checksum = bswap32(s->c_checksum); 1749 1.48 fvdl 1750 1.48 fvdl s->c_mode = bswap16(s->c_mode); 1751 1.71 christos s->c_extsize = bswap64(s->c_extsize); 1752 1.48 fvdl s->c_size = bswap64(s->c_size); 1753 1.48 fvdl s->c_old_atime = bswap32(s->c_old_atime); 1754 1.48 fvdl s->c_atimensec = bswap32(s->c_atimensec); 1755 1.48 fvdl s->c_old_mtime = bswap32(s->c_old_mtime); 1756 1.48 fvdl s->c_mtimensec = bswap32(s->c_mtimensec); 1757 1.48 fvdl s->c_rdev = bswap32(s->c_rdev); 1758 1.48 fvdl s->c_birthtimensec = bswap32(s->c_birthtimensec); 1759 1.48 fvdl s->c_birthtime = bswap64(s->c_birthtime); 1760 1.48 fvdl s->c_atime = bswap64(s->c_atime); 1761 1.48 fvdl s->c_mtime = bswap64(s->c_mtime); 1762 1.48 fvdl s->c_file_flags = bswap32(s->c_file_flags); 1763 1.48 fvdl s->c_uid = bswap32(s->c_uid); 1764 1.48 fvdl s->c_gid = bswap32(s->c_gid); 1765 1.48 fvdl 1766 1.48 fvdl s->c_count = bswap32(s->c_count); 1767 1.48 fvdl s->c_level = bswap32(s->c_level); 1768 1.48 fvdl s->c_flags = bswap32(s->c_flags); 1769 1.48 fvdl s->c_old_firstrec = bswap32(s->c_old_firstrec); 1770 1.48 fvdl 1771 1.48 fvdl s->c_date = bswap64(s->c_date); 1772 1.48 fvdl s->c_ddate = bswap64(s->c_ddate); 1773 1.48 fvdl s->c_tapea = bswap64(s->c_tapea); 1774 1.48 fvdl s->c_firstrec = bswap64(s->c_firstrec); 1775 1.10 cgd 1776 1.48 fvdl /* 1777 1.48 fvdl * These are ouid and ogid. 1778 1.48 fvdl */ 1779 1.48 fvdl s->c_spare1[1] = bswap16(s->c_spare1[1]); 1780 1.48 fvdl s->c_spare1[2] = bswap16(s->c_spare1[2]); 1781 1.10 cgd } 1782 1.10 cgd 1783 1.48 fvdl static void 1784 1.48 fvdl swap_old_header(struct s_ospcl *os) 1785 1.10 cgd { 1786 1.48 fvdl os->c_type = bswap32(os->c_type); 1787 1.48 fvdl os->c_date = bswap32(os->c_date); 1788 1.48 fvdl os->c_ddate = bswap32(os->c_ddate); 1789 1.48 fvdl os->c_volume = bswap32(os->c_volume); 1790 1.48 fvdl os->c_tapea = bswap32(os->c_tapea); 1791 1.48 fvdl os->c_inumber = bswap16(os->c_inumber); 1792 1.48 fvdl os->c_magic = bswap32(os->c_magic); 1793 1.48 fvdl os->c_checksum = bswap32(os->c_checksum); 1794 1.48 fvdl 1795 1.48 fvdl os->c_odinode.odi_mode = bswap16(os->c_odinode.odi_mode); 1796 1.48 fvdl os->c_odinode.odi_nlink = bswap16(os->c_odinode.odi_nlink); 1797 1.48 fvdl os->c_odinode.odi_uid = bswap16(os->c_odinode.odi_uid); 1798 1.48 fvdl os->c_odinode.odi_gid = bswap16(os->c_odinode.odi_gid); 1799 1.48 fvdl 1800 1.48 fvdl os->c_odinode.odi_size = bswap32(os->c_odinode.odi_size); 1801 1.48 fvdl os->c_odinode.odi_rdev = bswap32(os->c_odinode.odi_rdev); 1802 1.48 fvdl os->c_odinode.odi_atime = bswap32(os->c_odinode.odi_atime); 1803 1.48 fvdl os->c_odinode.odi_mtime = bswap32(os->c_odinode.odi_mtime); 1804 1.48 fvdl os->c_odinode.odi_ctime = bswap32(os->c_odinode.odi_ctime); 1805 1.10 cgd 1806 1.48 fvdl os->c_count = bswap32(os->c_count); 1807 1.10 cgd } 1808