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 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 #include <sys/param.h> 43 #include <signal.h> 44 #include <sys/types.h> 45 #include <sys/sysmacros.h> 46 #include <sys/vnode.h> 47 #include <sys/fs/ufs_fsdir.h> 48 #include <sys/fs/ufs_inode.h> 49 #include <sys/fs/ufs_fs.h> 50 #include <sys/stat.h> 51 #include <sys/statvfs.h> 52 #include <fcntl.h> 53 #include <stdio.h> 54 #include <unistd.h> 55 #include <stdlib.h> 56 #include <errno.h> 57 #include <signal.h> 58 #include <stdarg.h> 59 #include <sys/errno.h> 60 #include <sys/utsname.h> 61 #include <sys/ipc.h> 62 #include <sys/sem.h> 63 #include <sys/shm.h> 64 #include <archives.h> 65 #include "volcopy.h" 66 67 #include <locale.h> 68 69 /* 70 * main I/O information structure, contains information for the 71 * source and destination files. 72 */ 73 74 struct file_info { 75 char *f_dev_p, /* name of device */ 76 *f_vol_p; /* volume name */ 77 int f_bsize, /* size to buffer I/O to */ 78 f_des, /* file descriptor */ 79 f_dev; /* device type (generic I/O library) */ 80 } In, Out; 81 82 83 int Sem_id[BUFCNT], /* semaphore ids for controlling shared memory */ 84 Shm_id[BUFCNT], /* shared memory identifier */ 85 *Cnts[BUFCNT]; /* an array of byte counts for shared memory */ 86 87 char Empty[BLKSIZ], /* empty memory used to clear sections of memory */ 88 *Buf[BUFCNT]; /* buffer pointers (possibly to shared memory) */ 89 90 struct sembuf Sem_buf, /* semaphore operation buffer */ 91 Rstsem_buf; /* semaphore reset operation buffer */ 92 93 typedef union { 94 char dummy[SBSIZE]; 95 struct fs sblk; 96 97 } sb_un; 98 99 sb_un isup, osup, tsup; 100 101 #define Isup isup.sblk 102 #define Osup osup.sblk 103 104 struct fs *Sptr = (struct fs *)&tsup.sblk; /* super-block pointer */ 105 106 char *Ifname, *Ifpack, *Ofname, *Ofpack; 107 struct volcopy_label V_labl; 108 109 char From_vol[VVOLLEN + 1], 110 To_vol[VVOLLEN + 1], 111 *Fsys_p; 112 113 static char *nolabel = ""; /* used when there is no room for label */ 114 115 int Blk_cnt = 1, /* Do I/O in (Blk_cnt * BLKSIZ) byte blocks */ 116 Blocks = 0, /* Number of blocks transferred */ 117 Bpi = 0, 118 Bufcnt, 119 Bufflg = 0, 120 Bufsz = BLKSIZ, 121 Disk_cnt = 1, /* Disk I/O (Disk_cnt * Blk_cnt * BLKSIZ) byte blocks */ 122 Drive_typ = 0, /* Flag for special tape drive types */ 123 Eomflg = 0, 124 Ipc = 0, 125 Itape, 126 M3b15 = 0, /* Machine types, set to 1 for the machine */ 127 M3b2 = 0, /* the command is executing on */ 128 Otape, 129 Pid = -1, 130 R_blks = 0, /* Number of blocks per tape reel */ 131 R_cur = 1, /* Current tape reel being processed */ 132 R_len = 0, /* Length in feet of tape reels */ 133 R_num = 0, /* Number of tape reels to be processed */ 134 Shell_esc = 1, /* Allow shell after delete -nosh (3b15) can disable */ 135 Yesflg = 0; 136 137 void (*singal())(); 138 long Fs, 139 Fstype; 140 141 time_t Tvec; 142 143 FILE *Devtty; 144 145 static void getinfs(), 146 getoutfs(); 147 148 static char *getfslabel(); 149 static char *getvolabel(); 150 static void prompt(int verify, const char *fmt, ...); 151 static void perr(int severity, const char *fmt, ...); 152 153 /* 154 * g_init(), g_read(), g_write() originally came from libgenIO, 155 * a totally obsolete device interface library, now deleted. 156 * volcopy should be deleted too, since it doesn't work. 157 */ 158 159 #define G_TM_TAPE 1 /* Tapemaster controller */ 160 #define G_XY_DISK 3 /* xy disks */ 161 #define G_SD_DISK 7 /* scsi sd disk */ 162 #define G_XT_TAPE 8 /* xt tapes */ 163 #define G_SF_FLOPPY 9 /* sf floppy */ 164 #define G_XD_DISK 10 /* xd disks */ 165 #define G_ST_TAPE 11 /* scsi tape */ 166 #define G_NS 12 /* noswap pseudo-dev */ 167 #define G_RAM 13 /* ram pseudo-dev */ 168 #define G_FT 14 /* tftp */ 169 #define G_HD 15 /* 386 network disk */ 170 #define G_FD 16 /* 386 AT disk */ 171 #define G_FILE 28 /* file, not a device */ 172 #define G_NO_DEV 29 /* device does not require special treatment */ 173 #define G_DEV_MAX 30 /* last valid device type */ 174 175 /* 176 * g_init: Determine the device being accessed, set the buffer size, 177 * and perform any device specific initialization. Since at this point 178 * Sun has no system call to read the configuration, the major numbers 179 * are assumed to be static and types are figured out as such. However, 180 * as a rough estimate, the buffer size for all types is set to 512 181 * as a default. 182 */ 183 static int 184 g_init(int *devtype, int *fdes) 185 { 186 major_t maj; 187 int bufsize; 188 struct stat64 st_buf; 189 struct statvfs64 stfs_buf; 190 191 *devtype = G_NO_DEV; 192 if (fstat64(*fdes, &st_buf) == -1) 193 return (-1); 194 if (!S_ISCHR(st_buf.st_mode) && !S_ISBLK(st_buf.st_mode)) { 195 if (S_ISFIFO(st_buf.st_mode)) 196 bufsize = 512; 197 else { 198 /* find block size for this file system */ 199 *devtype = G_FILE; 200 if (fstatvfs64(*fdes, &stfs_buf) < 0) { 201 bufsize = -1; 202 errno = ENODEV; 203 } else { 204 bufsize = stfs_buf.f_bsize; 205 } 206 } 207 return (bufsize); 208 } 209 210 return (512); 211 } 212 213 /* 214 * g_read: Read nbytes of data from fdes (of type devtype) and place 215 * data in location pointed to by buf. In case of end of medium, 216 * translate (where necessary) device specific EOM indications into 217 * the generic EOM indication of rv = -1, errno = ENOSPC. 218 */ 219 /* ARGSUSED */ 220 static ssize_t 221 g_read(int devtype, int fdes, void *buf, size_t nbytes) 222 { 223 ssize_t rv; 224 225 rv = read(fdes, buf, nbytes); 226 227 /* st devices return 0 when no space left */ 228 if ((rv == 0 && errno == 0) || (rv == -1 && errno == EIO)) { 229 errno = ENOSPC; 230 rv = -1; 231 } 232 233 return (rv); 234 } 235 236 /* 237 * g_write: Write nbytes of data to fdes (of type devtype) from 238 * the location pointed to by buf. In case of end of medium, 239 * translate (where necessary) device specific EOM indications into 240 * the generic EOM indication of rv = -1, errno = ENOSPC. 241 */ 242 /* ARGSUSED */ 243 static ssize_t 244 g_write(int devtype, int fdes, void *buf, size_t nbytes) 245 { 246 ssize_t rv; 247 248 rv = write(fdes, buf, nbytes); 249 250 /* st devices return 0 when no more space left */ 251 if ((rv == 0 && errno == 0) || (rv == -1 && errno == EIO)) { 252 errno = ENOSPC; 253 rv = -1; 254 } 255 256 return (rv); 257 } 258 259 /* 260 * filesystem copy with propagation of volume ID and filesystem name: 261 * 262 * volcopy [-options] filesystem /dev/from From_vol /dev/to To_vol 263 * 264 * options are: 265 * -feet - length of tape 266 * -bpi - recording density 267 * -reel - reel number (if not starting from beginning) 268 * -buf - use double buffered i/o (if dens >= 1600 bpi) 269 * -block - Set the transfer block size to NUM physical blocks (512 270 * bytes on 3B2 and 3B15). Note that an arbitrary block size might 271 * or might not work on a given system. Also, the block size 272 * read from the header of an input tape silently overrides this. 273 * -nosh - Don't offer the user a shell after hitting break or delete. 274 * -r - Read NUM transfer blocks from the disk at once and write it 275 * to the output device one block at a time. Intended only to 276 * boost the 3B15 EDFC disk to tape performance. Disabled on 3B2. 277 * -a - ask "y or n" instead of "DEL if wrong" 278 * -s - inverse of -a, from/to devices are printed followed by `?'. 279 * User has 10 seconds to DEL if mistaken! 280 * -y - assume "yes" response to all questions 281 * 282 * Examples: 283 * 284 * volcopy root /dev/rdsk/0s2 pk5 /dev/rdsk/1s2 pk12 285 * 286 * volcopy u3 /dev/rdsk/1s5 pk1 /dev/rmt/0m tp123 287 * 288 * volcopy u5 /dev/rmt/0m - /dev/rdsk/1s5 - 289 */ 290 291 main(argc, argv) 292 int argc; 293 char **argv; 294 { 295 register char c; 296 register int lfdes, altflg = 0, result, verify; 297 register long dist; 298 char *align(); 299 void sigalrm(), sigint(); 300 struct stat stbuf; 301 int cnt; 302 303 (void) setlocale(LC_ALL, ""); 304 #if !defined(TEXT_DOMAIN) 305 #define TEXT_DOMAIN "SYS_TEST" 306 #endif 307 (void) textdomain(TEXT_DOMAIN); 308 309 (void) get_mach_type(); 310 (void) signal(SIGINT, sigint); 311 (void) signal(SIGALRM, sigalrm); 312 In.f_bsize = Out.f_bsize = BLKSIZ; 313 while (argc > 1 && argv[1][0] == '-') { 314 if (EQ(argv[1], "-a", 2)) { 315 altflg |= MINUSA; 316 } else if (EQ(argv[1], "-e", 2)) { 317 Eomflg = 1; 318 } else if (EQ(argv[1], "-s", 2)) { 319 altflg |= MINUSS; 320 } else if (EQ(argv[1], "-y", 2)) { 321 Yesflg++; 322 } else if (EQ(argv[1], "-buf", 4)) { 323 Bufflg++; 324 } else if (EQ(argv[1], "-bpi", 4)) { 325 if ((c = argv[1][4]) >= '0' && c <= '9') 326 Bpi = getbpi(&argv[1][4]); 327 else { 328 ++argv; 329 --argc; 330 Bpi = getbpi(&argv[1][0]); 331 } 332 } else if (EQ(argv[1], "-feet", 5)) { 333 if ((c = argv[1][5]) >= '0' && c <= '9') 334 R_len = atoi(&argv[1][5]); 335 else { 336 ++argv; 337 --argc; 338 R_len = atoi(&argv[1][0]); 339 } 340 } else if (EQ(argv[1], "-reel", 5)) { 341 if ((c = argv[1][5]) >= '0' && c <= '9') 342 R_cur = atoi(&argv[1][5]); 343 else { 344 ++argv; 345 --argc; 346 R_cur = atoi(&argv[1][0]); 347 } 348 } else if (EQ(argv[1], "-r", 2)) { /* 3b15 only */ 349 if ((c = argv[1][2]) >= '0' && c <= '9') 350 Disk_cnt = atoi(&argv[1][2]); 351 else { 352 ++argv; 353 --argc; 354 Disk_cnt = atoi(&argv[1][0]); 355 } 356 if (Disk_cnt == 0) 357 perr(1, "volcopy: Need a non-zero value for the -r option\n"); 358 } else if (EQ(argv[1], "-block", 6)) { /* 3b15 only */ 359 if ((c = argv[1][6]) >= '0' && c <= '9') 360 Blk_cnt = atoi(&argv[1][6]); 361 else { 362 ++argv; 363 --argc; 364 Blk_cnt = atoi(&argv[1][0]); 365 } 366 if (Blk_cnt == 0) 367 perr(1, "volcopy: Need a non-zero value for the -block option\n"); 368 } else if (EQ(argv[1], "-nosh", 5)) { /* 3b15 only */ 369 Shell_esc = 0; 370 } else 371 perr(1, "<%s> invalid option\n", argv[1]); 372 ++argv; 373 --argc; 374 } /* argv[1][0] == '-' */ 375 376 Devtty = fopen("/dev/tty", "r"); 377 if ((Devtty == NULL) && !isatty(0)) 378 Devtty = stdin; 379 time(&Tvec); 380 381 if (Eomflg && R_len) 382 perr(9, "volcopy: -e and -feet are mutually exclusive\n"); 383 if ((altflg & MINUSA) && (altflg & MINUSS)) 384 perr(9, "volcopy: -a and -s are mutually exclusive\n"); 385 if (argc != 6) /* if mandatory fields not present */ 386 perr(9, "ufs usage: volcopy [-F ufs] [generic options] \ 387 fsname /devfrom volfrom /devto volto\n"); 388 if (!(altflg & MINUSA)) /* -a was not specified, use default (-s) */ 389 altflg |= MINUSS; 390 391 In.f_dev_p = argv[DEV_IN]; 392 Out.f_dev_p = argv[DEV_OUT]; 393 strncpy(To_vol, argv[VOL_OUT], VVOLLEN); 394 To_vol[VVOLLEN] = '\0'; 395 Out.f_vol_p = &To_vol[0]; 396 strncpy(From_vol, argv[VOL_IN], VVOLLEN); 397 From_vol[VVOLLEN] = '\0'; 398 In.f_vol_p = &From_vol[0]; 399 Fsys_p = argv[FIL_SYS]; 400 401 if ((In.f_des = open(In.f_dev_p, O_RDONLY)) < 1) 402 perr(10, "%s: cannot open\n", In.f_dev_p); 403 if ((Out.f_des = open(Out.f_dev_p, O_RDONLY)) < 1) 404 perr(10, "%s: cannot open\n", Out.f_dev_p); 405 406 if (fstat(In.f_des, &stbuf) < 0 || (stbuf.st_mode & S_IFMT) != S_IFCHR) 407 perr(10, "From device not character-special\n"); 408 if (fstat(Out.f_des, &stbuf) < 0 || (stbuf.st_mode & S_IFMT) != S_IFCHR) 409 perr(10, "To device not character-special\n"); 410 411 if ((Itape = tapeck(&In, INPUT)) == 1) 412 R_blks = V_labl.v_reelblks; 413 Otape = tapeck(&Out, OUTPUT); 414 if (Otape && Itape) 415 perr(10, "Use dd(1) command to copy tapes\n"); 416 (void) mem_setup(); 417 if (Bufflg && !Ipc) 418 perr(1, "The -buf option requires ipc\n"); 419 if (!Itape && !Otape) 420 R_cur = 1; 421 if (R_cur == 1 || !Itape) { 422 /* read in superblock */ 423 verify = 0; 424 (void) getinfs(In.f_dev, In.f_des, Sptr); 425 426 if ((Sptr->fs_magic != FS_MAGIC) && 427 (Sptr->fs_magic != MTB_UFS_MAGIC)) 428 perr(10, "File System type unknown--get help\n"); 429 430 if (Sptr->fs_magic == FS_MAGIC && 431 (Sptr->fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 && 432 Sptr->fs_version != UFS_VERSION_MIN)) 433 perr(10, "Unrecognized version of UFS--get help\n"); 434 435 if (Sptr->fs_magic == MTB_UFS_MAGIC && 436 (Sptr->fs_version > MTB_UFS_VERSION_1 || 437 Sptr->fs_version < MTB_UFS_VERSION_MIN)) 438 perr(10, "Unrecognized version of UFS--get help\n"); 439 440 (void) memcpy(&Isup, Sptr, Sptr->fs_sbsize); 441 Ifname = getfslabel(&Isup); 442 Ifpack = getvolabel(&Isup); 443 Fs = Sptr->fs_size * Sptr->fs_nspf; 444 } /* R_cur == 1 || !Itape */ 445 446 /* read in superblock */ 447 verify = !Otape || (altflg & MINUSS); 448 (void) getoutfs(Out.f_dev, Out.f_des, Sptr, verify); 449 450 if ((Sptr->fs_magic == FS_MAGIC) || (Sptr->fs_magic == MTB_UFS_MAGIC)) { 451 (void) memcpy(&Osup, Sptr, Sptr->fs_sbsize); 452 Ofname = getfslabel(&Osup); 453 Ofpack = getvolabel(&Osup); 454 } else { 455 int i; 456 457 /* out vol does not contain a ufs file system */ 458 /* stuff let over from Isup */ 459 (void) memcpy(&Osup, &Isup, Isup.fs_sbsize); 460 Ofname = getfslabel(&Osup); 461 Ofpack = getvolabel(&Osup); 462 /* wipe out the fs name and pack name for warning purposes */ 463 for (i = 0; i < 6; i++) Ofname[i] = ' '; 464 for (i = 0; i < 6; i++) Ofpack[i] = ' '; 465 } 466 467 if (Itape) { 468 if (R_cur != 1) { 469 (void) printf(gettext( 470 "\nvolcopy: IF REEL 1 HAS NOT BEEN RESTORED,")); 471 (void) printf(gettext( 472 " STOP NOW AND START OVER ***\07\n")); 473 if (!ask(" Continue? ")) { 474 cleanup(); 475 exit(31+9); 476 } 477 strncpy(Ifname, Fsys_p, 6); 478 strncpy(Ifpack, In.f_vol_p, 6); 479 } 480 if (V_labl.v_reel != R_cur || V_labl.v_reels != R_num) 481 prompt(1, "Tape disagrees: Reel %d of %d : looking for %d of %d\n", 482 V_labl.v_reel, V_labl.v_reels, R_cur, R_num); 483 } else if (Otape) { 484 strncpy(V_labl.v_volume, Out.f_vol_p, 6); 485 strncpy(Ofpack, Out.f_vol_p, 6); 486 strncpy(Ofname, Fsys_p, 6); 487 if (!Eomflg) { 488 R_num = Fs / R_blks + ((Fs % R_blks) ? 1 : 0); 489 (void) printf(gettext( 490 "You will need %d reels.\n"), R_num); 491 (void) printf(gettext( 492 "(\tThe same size and density is expected for all reels)\n")); 493 } 494 } 495 if (NOT_EQ(Fsys_p, Ifname, 6)) { 496 verify = !Otape || (altflg & MINUSS); 497 prompt(verify, 498 "arg. (%.6s) doesn't agree with from fs. (%.6s)\n", 499 Fsys_p, Ifname); 500 } 501 if (NOT_EQ(In.f_vol_p, "-", 6) && NOT_EQ(In.f_vol_p, Ifpack, 6)) { 502 verify = !Otape || (altflg & MINUSS); 503 prompt(verify, "arg. (%.6s) doesn't agree with from vol.(%.6s)\n", 504 In.f_vol_p, Ifpack); 505 } 506 507 if (*In.f_vol_p == '-') 508 In.f_vol_p = Ifpack; 509 if (*Out.f_vol_p == '-') 510 Out.f_vol_p = Ofpack; 511 512 if (R_cur == 1 && (Osup.fs_time + _2_DAYS) > Isup.fs_time) { 513 time_t t; 514 515 verify = altflg & MINUSS; 516 t = (time_t)Osup.fs_time; 517 prompt(verify, "%s less than 48 hours older than %s\n" 518 "To filesystem dated: %s", 519 Out.f_dev_p, In.f_dev_p, ctime(&t)); 520 } 521 if (NOT_EQ(Out.f_vol_p, Ofpack, 6)) { 522 prompt(1, "arg.(%.6s) doesn't agree with to vol.(%.6s)\n", 523 Out.f_vol_p, Ofpack); 524 strncpy(Ofpack, Out.f_vol_p, 6); 525 } 526 if (Isup.fs_size > Osup.fs_size && !Otape) 527 prompt(1, "from fs larger than to fs\n"); 528 if (!Otape && NOT_EQ(Ifname, Ofname, 6)) { 529 verify = altflg & MINUSS; 530 prompt(verify, "warning! from fs(%.6s) differs from to fs(%.6s)\n", 531 Ifname, Ofname); 532 } 533 534 (void) printf(gettext("From: %s, to: %s? "), In.f_dev_p, Out.f_dev_p); 535 if (!(altflg & MINUSA)) { 536 (void) printf(gettext("(DEL if wrong)\n")); 537 sleep(10); 538 } else if (!ask("(y or n) ")) 539 perr(10, "\nvolcopy: STOP\n"); 540 close(In.f_des); 541 close(Out.f_des); 542 sync(); 543 In.f_des = open(In.f_dev_p, O_RDONLY); 544 Out.f_des = open(Out.f_dev_p, O_WRONLY); 545 errno = 0; 546 if (g_init(&In.f_dev, &In.f_des) < 0 || 547 g_init(&Out.f_dev, &Out.f_des) < 0) 548 perr(1, "volcopy: Error %d during initialization\n", errno); 549 if (Itape) { 550 errno = 0; 551 if (g_read(In.f_dev, In.f_des, &V_labl, sizeof (V_labl)) < 552 sizeof (V_labl)) 553 perr(10, "Error while reading label\n"); 554 } else if (Otape) { 555 V_labl.v_reels = R_num; 556 V_labl.v_reel = R_cur; 557 V_labl.v_time = Tvec; 558 V_labl.v_reelblks = R_blks; 559 V_labl.v_blksize = BLKSIZ * Blk_cnt; 560 V_labl.v_nblocks = Blk_cnt; 561 V_labl.v_offset = 0L; 562 V_labl.v_type = T_TYPE; 563 errno = 0; 564 if (g_write(Out.f_dev, Out.f_des, &V_labl, sizeof (V_labl)) < 565 sizeof (V_labl)) 566 perr(10, "Error while writing label\n"); 567 } 568 if (R_cur > 1) { 569 if (!Eomflg) { 570 Fs = (R_cur - 1) * actual_blocks(); 571 lfdes = Otape ? In.f_des : Out.f_des; 572 dist = (long)(Fs * BLKSIZ); 573 } else { /* Eomflg */ 574 if (Otape) 575 perr(1, "Cannot use -reel with -e when copying to tape\n"); 576 lfdes = Out.f_des; 577 dist = (long)(V_labl.v_offset * BLKSIZ); 578 Fs = V_labl.v_offset; 579 } 580 if (lseek(lfdes, dist, 0) < 0) 581 perr(1, "Cannot lseek()\n"); 582 Sptr = Otape ? &Isup : &Osup; 583 if ((Sptr -> fs_magic != FS_MAGIC) && 584 (Sptr -> fs_magic != MTB_UFS_MAGIC)) 585 perr(10, "File System type unknown--get help!\n"); 586 587 if (Sptr->fs_magic == FS_MAGIC && 588 (Sptr->fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 && 589 Sptr->fs_version != UFS_VERSION_MIN)) 590 perr(10, "Unrecognized version of UFS--get help\n"); 591 592 if (Sptr->fs_magic == MTB_UFS_MAGIC && 593 (Sptr->fs_version > MTB_UFS_VERSION_1 || 594 Sptr->fs_version < MTB_UFS_VERSION_MIN)) 595 perr(10, "Unrecognized version of UFS--get help\n"); 596 597 Fs = (Sptr->fs_size * Sptr->fs_nspf) - Fs; 598 } 599 if (Itape || Otape) 600 rprt(); 601 602 if (Ipc) { 603 parent_copy(); 604 (void) cleanup(); 605 } else 606 copy(); 607 (void) printf(gettext(" END: %ld blocks.\n"), Blocks); 608 609 #ifdef LOG 610 fslog(); 611 #endif 612 if (Blocks) 613 exit(0); 614 exit(31+1); /* failed.. 0 blocks */ 615 } 616 617 /* 618 * sigalrm: catch alarm signals. 619 */ 620 621 void 622 sigalrm() 623 { 624 void (*signal())(); 625 626 (void) signal(SIGALRM, sigalrm); 627 } 628 629 /* 630 * sigsys: catch illegal system calls to determine if IPC is available. 631 */ 632 633 void 634 sigsys() 635 { 636 637 Ipc = 0; 638 } 639 640 /* 641 * sigint: catch interrupts and prompt user for shell or to quit. 642 */ 643 644 void 645 sigint() 646 { 647 void (*signal())(); 648 extern char **environ; 649 register int tmpflg, i = 0, ps1 = -1, ps2 = -1; 650 651 tmpflg = Yesflg; /* override yesflag for duration of interrupt */ 652 Yesflg = 0; 653 if (Shell_esc && ask("Want Shell? ")) { 654 if (!fork()) { 655 /* both PS1 and PS2 must be exported */ 656 while (environ[i]) { 657 if (EQ(environ[i], "PS1", 3)) 658 ps1 = i; 659 if (EQ(environ[i], "PS2", 3)) 660 ps2 = i; 661 i++; 662 } 663 if (ps1 >= 0 && ps2 >= 0) 664 environ[ps1] = environ[ps2]; 665 (void) signal(SIGINT, SIG_DFL); 666 execl("/usr/bin/sh", "/usr/bin/sh", 0); 667 } else { /* parent */ 668 (void) signal(SIGINT, SIG_IGN); 669 wait((int *)0); 670 } 671 } else if (ask("Want to quit? ")) { 672 if (Pid > 0) 673 kill(Pid, 9); 674 (void) cleanup(); /* ipc */ 675 exit(31+2); 676 } 677 (void) signal(SIGINT, sigint); 678 Yesflg = tmpflg; /* reset Yesflg */ 679 } 680 681 /* 682 * actual_blocks: Calculate the actual number of blocks written to 683 * the tape (will differ from V_labl.v_reelblks if v_reelblks is not 684 * an even multiple of the blocking factor Blk_cnt). 685 */ 686 687 int 688 actual_blocks() 689 { 690 691 if (R_blks % Blk_cnt) 692 return (((R_blks / Blk_cnt) + 1) * Blk_cnt); 693 else 694 return (R_blks); 695 } 696 697 /* 698 * get_mach_type: Determine what machine this is executing on. 699 */ 700 701 int 702 get_mach_type() 703 { 704 struct utsname utsinfo; 705 706 errno = 0; 707 if (uname(&utsinfo) < 0) 708 perr(1, "Unable to determine machine type\n"); 709 if (strcmp(utsinfo.machine, "3B2") == 0) 710 M3b2 = 1; 711 else if (strcmp(utsinfo.machine, "3B15") == 0) 712 M3b15 = 1; 713 } 714 715 /* 716 * mem_setup: Determine memory needs and check for IPC. If IPC is available, 717 * used shared memory and semaphores to increase performance. If no IPC, 718 * get normal memory and only use one process. 719 */ 720 721 int 722 mem_setup() 723 { 724 void (*signal())(); 725 register int cnt, num, size; 726 char *align(); 727 728 union semun { 729 int val; 730 struct semid_ds *buf; 731 ushort_t *array; 732 } sem_arg; 733 734 if (Blk_cnt == 1) { 735 switch (Drive_typ) { 736 case A_DRIVE: 737 Blk_cnt = 32; 738 break; 739 case C_DRIVE: 740 Blk_cnt = 10; 741 break; 742 case K_DRIVE: 743 Blk_cnt = 4; 744 break; 745 case T_DRIVE: 746 if (Bpi == 6250) 747 Blk_cnt = 50; 748 else 749 Blk_cnt = 10; 750 break; 751 default: 752 if (M3b15) { 753 if (Itape || Otape) 754 Blk_cnt = 16; 755 } else { 756 if (Otape || Itape) { 757 if (Bpi == 6250) 758 Blk_cnt = 50; 759 else 760 Blk_cnt = 10; 761 } 762 } 763 break; 764 } /* Drive_typ */ 765 } /* Blk_cnt == 1 */ 766 if (Blk_cnt > 1) /* user overrode g_init */ 767 In.f_bsize = Out.f_bsize = Blk_cnt * BLKSIZ; 768 In.f_bsize = (!Itape) ? Disk_cnt * In.f_bsize : In.f_bsize; 769 Out.f_bsize = (!Otape) ? Disk_cnt * Out.f_bsize : Out.f_bsize; 770 Bufsz = find_lcm(In.f_bsize, Out.f_bsize); 771 num = _128K / (Bufsz + sizeof (int)); 772 Bufsz *= num; 773 size = Bufsz + sizeof (int); 774 /* test to see if ipc is available, the shmat should fail with EINVAL */ 775 (void) signal(SIGSYS, sigsys); 776 errno = 0; 777 if (Ipc) { 778 if ((int)shmat(0, (char *)NULL, 0) < 0 && errno != EINVAL) 779 Ipc = 0; /* something went wrong */ 780 } 781 if (Ipc) { /* ipc is available */ 782 Bufcnt = 2; 783 sem_arg.val = 0; 784 for (cnt = 0; cnt < BUFCNT; cnt++) { 785 errno = 0; 786 if ((Sem_id[cnt] = semget(IPC_PRIVATE, 1, 0)) < 0) 787 perr(1, "Error allocating semaphores: %d", 788 errno); 789 if (semctl(Sem_id[cnt], 0, SETVAL, sem_arg) < 0) 790 perr(1, "Error setting semaphores: %d", errno); 791 if ((Shm_id[cnt] = shmget(IPC_PRIVATE, size, 0)) < 0) 792 perr(1, "Error allocating shared memory: %d", 793 errno); 794 if ((Buf[cnt] = shmat(Shm_id[cnt], 0, 0)) == (void *)-1) 795 perr(1, "Error attaching shared memory: %d", 796 errno); 797 if (shmctl(Shm_id[cnt], SHM_LOCK, 0) < 0) 798 perr(0, "Error locking in shared memory: %d", 799 errno); 800 Cnts[cnt] = (int *)(Buf[cnt] + Bufsz); 801 } 802 } else { /* ipc is not available */ 803 Bufcnt = 1; 804 if ((Buf[0] = align(size)) == (char *)NULL) 805 perr(1, "Out of memory\n"); 806 Cnts[0] = (int *)(Buf[0] + Bufsz); 807 *Cnts[0] = 0; 808 } 809 } 810 811 /* 812 * prompt: Prompt the user for verification. 813 */ 814 815 static void 816 prompt(int verify, const char *fmt, ...) 817 { 818 va_list ap; 819 820 va_start(ap, fmt); 821 if (fmt != NULL) 822 (void) vfprintf(stdout, gettext(fmt), ap); 823 va_end(ap); 824 if (verify) { 825 (void) fprintf(stdout, gettext("Type 'y' to override: ")); 826 if (!ask("")) { 827 cleanup(); 828 exit(31+9); 829 } 830 } 831 } 832 833 /* 834 * ask: Ask the user a question and get the answer. 835 */ 836 837 ask(s) 838 char *s; 839 { 840 char ans[12]; 841 842 (void) printf(gettext(s)); 843 if (Yesflg) { 844 (void) printf(gettext("YES\n")); 845 return (1); 846 } 847 ans[0] = '\0'; 848 fgets(ans, 10, Devtty); 849 for (;;) { 850 switch (ans[0]) { 851 case 'a': 852 case 'A': 853 if (Pid > 0) /* parent with a child */ 854 kill(Pid, 9); 855 cleanup(); 856 exit(31+1); 857 case 'y': 858 case 'Y': 859 return (1); 860 case 'n': 861 case 'N': 862 return (0); 863 default: 864 (void) printf(gettext("\n(y or n)?")); 865 fgets(ans, 10, Devtty); 866 } 867 } 868 } 869 870 /* 871 * align: Align a malloc'd memory section on a page boundry. 872 */ 873 874 char * 875 align(size) 876 register int size; 877 { 878 register int pad; 879 880 if ((pad = ((int)malloc(0) & (PAGESIZE-1))) > 0) { 881 pad = PAGESIZE - pad; 882 if (malloc(pad) == (char *)NULL) 883 return ((char *)NULL); 884 } 885 return (malloc((unsigned)size)); 886 } 887 888 /* 889 * child_copy: Using IPC, this child process reads from shared memory 890 * and writes to the destination file system. 891 */ 892 893 int 894 child_copy() 895 { 896 register int rv, cur_buf, left, have, tpcnt; 897 register char *c_p; 898 899 (void) signal(SIGINT, SIG_IGN); 900 Sem_buf.sem_op = -1; 901 (void) close(In.f_des); 902 if (Otape && !Eomflg) 903 tpcnt = actual_blocks() * BLKSIZ; 904 cur_buf = 0; 905 for (;;) { 906 if (semop(Sem_id[cur_buf], &Sem_buf, 1) < 0) 907 perr(1, "semaphore operation error %d\n", errno); 908 left = *Cnts[cur_buf]; 909 if (!left) 910 break; 911 c_p = Buf[cur_buf]; 912 rv = 0; 913 while (left) { 914 have = (left < Out.f_bsize) ? left : Out.f_bsize; 915 if (!Eomflg && Otape) { 916 if (!tpcnt) { 917 (void) chgreel(&Out, OUTPUT); 918 tpcnt = actual_blocks() * BLKSIZ; 919 } 920 have = (tpcnt < have) ? tpcnt : have; 921 } 922 errno = 0; 923 if ((rv = g_write(Out.f_dev, Out.f_des, c_p, have)) < 924 0) { 925 if (Eomflg && errno == ENOSPC) { 926 (void) chgreel(&Out, OUTPUT); 927 continue; 928 } else 929 perr(1, "I/O error %d on write\n", 930 errno); 931 } 932 left -= rv; 933 c_p += rv; 934 V_labl.v_offset += rv; 935 if (!Eomflg && Otape) 936 tpcnt -= rv; 937 } 938 if (semop(Sem_id[cur_buf], &Sem_buf, 1) < 0) 939 perr(2, "semaphore operation error %d\n", errno); 940 cur_buf = (cur_buf + 1) % BUFCNT; 941 } 942 exit(0); 943 } 944 945 /* 946 * parent_copy: Using shared memory, the parent process reads fromt the 947 * source file system and writes to shared memory. 948 */ 949 950 int 951 parent_copy() 952 { 953 register int rv, left, have, tpcnt, cur_buf; 954 register char *c_p; 955 int eom = 0, xfer_cnt = Fs * BLKSIZ; 956 957 Sem_buf.sem_num = 0; 958 Sem_buf.sem_flg = 0; 959 if ((Pid = fork()) == 0) 960 child_copy(); /* child does not return */ 961 (void) close(Out.f_des); 962 Rstsem_buf.sem_num = 0; 963 Rstsem_buf.sem_flg = 0; 964 Rstsem_buf.sem_op = 2; 965 Sem_buf.sem_op = 0; 966 cur_buf = 0; 967 if (Itape && !Eomflg) 968 tpcnt = actual_blocks() * BLKSIZ; 969 while (xfer_cnt) { 970 if (semop(Sem_id[cur_buf], &Sem_buf, 1) < 0) 971 perr(1, "Semaphore operation error %d\n", errno); 972 c_p = Buf[cur_buf]; 973 left = Bufsz; 974 rv = 0; 975 while (left >= In.f_bsize && xfer_cnt) { 976 have = (xfer_cnt < In.f_bsize) ? xfer_cnt : In.f_bsize; 977 if (!Eomflg && Itape) { 978 if (!tpcnt) { 979 *Cnts[cur_buf] = Bufsz - left; 980 (void) flush_bufs(cur_buf); 981 (void) chgreel(&In, INPUT); 982 tpcnt = actual_blocks() * BLKSIZ; 983 cur_buf = (cur_buf == 0) ? 1 : 0; 984 eom = 1; 985 break; 986 } 987 have = (tpcnt < have) ? tpcnt : have; 988 } 989 errno = 0; 990 if ((rv = g_read(In.f_dev, In.f_des, c_p, have)) < 0) { 991 if (Eomflg && errno == ENOSPC) { 992 *Cnts[cur_buf] = Bufsz - left; 993 (void) flush_bufs(cur_buf); 994 (void) chgreel(&In, INPUT); 995 cur_buf = (cur_buf == 0) ? 1 : 0; 996 eom = 1; 997 break; 998 } else 999 perr(1, "I/O error %d on read\n", 1000 errno); 1001 } 1002 left -= rv; 1003 c_p += rv; 1004 xfer_cnt -= rv; 1005 if (!Eomflg && Itape) 1006 tpcnt -= rv; 1007 } 1008 if (eom > 0) { 1009 eom = 0; 1010 if (Eomflg) 1011 xfer_cnt -= rv; 1012 else if (Itape) 1013 tpcnt -= rv; 1014 continue; 1015 } 1016 *Cnts[cur_buf] = Bufsz - left; 1017 Blocks += *Cnts[cur_buf]; 1018 if (semop(Sem_id[cur_buf], &Rstsem_buf, 1) < 0) 1019 perr(2, "Semaphore operation error %d\n", errno); 1020 cur_buf = (cur_buf == 0) ? 1 : 0; 1021 } 1022 if (semop(Sem_id[cur_buf], &Sem_buf, 1) < 0) 1023 perr(3, "Semaphore operation error %d\n", errno); 1024 *Cnts[cur_buf] = 0; 1025 if (semop(Sem_id[cur_buf], &Rstsem_buf, 1) < 0) 1026 perr(4, "Semaphore operation error %d\n", errno); 1027 wait((int *)NULL); 1028 Blocks /= BLKSIZ; 1029 } 1030 1031 /* 1032 * copy: Copy without shared memory. The process reads from the source 1033 * filesystem and writes to the destination filesystem. 1034 */ 1035 1036 int 1037 copy() 1038 { 1039 register int rv, left, have, tpcnt = 1, xfer_cnt = Fs * BLKSIZ; 1040 register char *c_p; 1041 1042 if ((Itape || Otape) && !Eomflg) 1043 tpcnt = actual_blocks() * BLKSIZ; 1044 while (xfer_cnt) { 1045 c_p = (char *)(Buf[0] + *Cnts[0]); 1046 left = Bufsz - *Cnts[0]; 1047 rv = 0; 1048 while (left >= In.f_bsize && xfer_cnt) { 1049 have = (xfer_cnt < In.f_bsize) ? xfer_cnt : In.f_bsize; 1050 if (!Eomflg && Itape) { 1051 if (!tpcnt) { 1052 *Cnts[0] = Bufsz - left; 1053 (void) chgreel(&In, INPUT); 1054 tpcnt = actual_blocks() * BLKSIZ; 1055 break; 1056 } 1057 have = (tpcnt < have) ? tpcnt : have; 1058 } 1059 errno = 0; 1060 if ((rv = g_read(In.f_dev, In.f_des, c_p, have)) < 0) { 1061 if (Eomflg && errno == ENOSPC) { 1062 (void) chgreel(&In, INPUT); 1063 break; 1064 } else 1065 perr(1, "I/O error %d on read\n", 1066 errno); 1067 } 1068 left -= rv; 1069 c_p += rv; 1070 xfer_cnt -= rv; 1071 if (!Eomflg && Itape) 1072 tpcnt -= rv; 1073 } /* left >= In.f_bsize && xfer_cnt */ 1074 *Cnts[0] = Bufsz - left; 1075 Blocks += *Cnts[0]; 1076 c_p = Buf[0]; 1077 left = *Cnts[0]; 1078 rv = 0; 1079 while (left >= Out.f_bsize || (left > 0 && !xfer_cnt)) { 1080 have = (left < Out.f_bsize) ? left : Out.f_bsize; 1081 if (!Eomflg && Otape) { 1082 if (!tpcnt) { 1083 (void) chgreel(&Out, OUTPUT); 1084 tpcnt = actual_blocks() * BLKSIZ; 1085 } 1086 have = (tpcnt < have) ? tpcnt : have; 1087 } 1088 errno = 0; 1089 if ((rv = g_write(Out.f_dev, Out.f_des, c_p, have)) < 1090 0) { 1091 if (Eomflg && errno == ENOSPC) { 1092 (void) chgreel(&Out, OUTPUT); 1093 continue; 1094 } else 1095 perr(1, "I/O error %d on write\n", 1096 errno); 1097 } 1098 left -= rv; 1099 c_p += rv; 1100 V_labl.v_offset += rv; 1101 if (!Eomflg && Otape) 1102 tpcnt -= rv; 1103 } /* left >= Out.f_bsize */ 1104 if (left) { 1105 (void) memcpy(Buf[0], c_p, left); 1106 Blocks -= left; 1107 } 1108 *Cnts[0] = left; 1109 } /* xfer_cnt */ 1110 Blocks /= BLKSIZ; 1111 } 1112 1113 /* 1114 * flush_bufs: Permit child to read the remaining data from the 1115 * buffer before prompting user for end-of-media. 1116 */ 1117 1118 int 1119 flush_bufs(buffer) 1120 register int buffer; 1121 { 1122 1123 Blocks += *Cnts[buffer]; 1124 if (semop(Sem_id[buffer], &Rstsem_buf, 1) < 0) 1125 perr(5, "Semaphore operation error %d\n", errno); 1126 if (semop(Sem_id[buffer], &Sem_buf, 1) < 0) 1127 perr(6, "Semaphore operation error %d\n", errno); 1128 } 1129 1130 /* 1131 * cleanup: Clean up shared memory and semaphore resources. 1132 */ 1133 1134 int 1135 cleanup() 1136 { 1137 register int cnt; 1138 1139 if (Ipc) { 1140 for (cnt = 0; cnt < BUFCNT; cnt++) { 1141 (void) semctl(Sem_id[cnt], IPC_RMID, 0); 1142 (void) shmctl(Shm_id[cnt], IPC_RMID, 0); 1143 } 1144 } 1145 } 1146 1147 /* 1148 * find_lcm: Find the lowest common multiple of two numbers. This is used 1149 * to determine the buffer size that should be malloc(3)'d such that the 1150 * input and output data blocks can both fit evenly into the buffer. 1151 */ 1152 1153 int 1154 find_lcm(sz1, sz2) 1155 register int sz1, sz2; 1156 { 1157 register int inc, lcm, small; 1158 1159 if (sz1 < sz2) { 1160 lcm = inc = sz2; 1161 small = sz1; 1162 } else { /* sz1 >= sz2 */ 1163 lcm = inc = sz1; 1164 small = sz2; 1165 } 1166 while (lcm % small != 0) 1167 lcm += inc; 1168 return (lcm); 1169 } 1170 1171 /* 1172 * Determine bpi information from drive names. 1173 */ 1174 1175 getbpi(inp) 1176 register char *inp; 1177 { 1178 1179 /* 1180 * Kludge to recognize Accellerated Tape Controller usage from 1181 * letter 'a' or 'A' following density given by user. 1182 * 1183 * Kludge to recognize 3B15 Compatibility Mode from 1184 * letter 'c' or 'C' following density given by user. 1185 */ 1186 if (M3b15) { 1187 if (inp[4] == 'a' || inp[4] == 'A') { 1188 Drive_typ = A_DRIVE; 1189 inp[4] = '\0'; 1190 } 1191 if (inp[4] == 'c' || inp[4] == 'C') { 1192 Drive_typ = C_DRIVE; 1193 inp[4] = '\0'; 1194 } 1195 } 1196 return (atoi(inp)); 1197 } 1198 1199 /* 1200 * blks_per_ft: Determine the number of blocks per foot of tape. 1201 * Inter-block gap (dgap) is 0.3 in. 1202 */ 1203 1204 int 1205 blks_per_ft(disc) 1206 register double disc; 1207 { 1208 register double dcnt = Blk_cnt, dBpi = Bpi, dsiz = BLKSIZ, dgap = 0.3; 1209 1210 return ((int)(dcnt / (((dcnt * dsiz / dBpi) + dgap) / 12.0) * disc)); 1211 } 1212 1213 /* 1214 * tapeck: Arbitrary block size. Determine the number of physical blocks per 1215 * foot of tape, including the inter-block gap, and the possibility of a short 1216 * tape. Assume the usable portion of a tape is 85% of its length for small 1217 * block sizes and 88% for large block sizes. 1218 */ 1219 1220 tapeck(f_p, dir) 1221 register struct file_info *f_p; 1222 register int dir; 1223 { 1224 register int again = 1, verify, old_style, new_style; 1225 char resp[16]; 1226 1227 errno = 0; 1228 if ((f_p->f_bsize = g_init(&f_p->f_dev, &f_p->f_des)) < 0) 1229 perr(1, "volcopy: Error %d during initialization\n", errno); 1230 if ((f_p->f_dev != G_TM_TAPE) && (f_p->f_dev != G_XT_TAPE) && 1231 (f_p->f_dev != G_ST_TAPE)) 1232 return (0); 1233 V_labl.v_magic[0] = '\0'; /* scribble on old data */ 1234 alarm(5); 1235 if (g_read(f_p->f_dev, f_p->f_des, &V_labl, sizeof (V_labl)) <= 0) { 1236 if (dir == INPUT) 1237 perror("input tape"); 1238 else 1239 perror("output tape"); 1240 } 1241 alarm(0); 1242 if (V_labl.v_reel == (char)NULL && dir == INPUT) 1243 perr(9, "Input tape is empty\n"); 1244 else { 1245 old_style = strncmp(V_labl.v_magic, "Volcopy", 7) == 0; 1246 new_style = strncmp(V_labl.v_magic, "VOLCOPY", 7) == 0; 1247 if (!old_style && !new_style) { 1248 verify = (dir == INPUT) ? 0 : 1; 1249 prompt(verify, "Not a labeled tape\n"); 1250 if (dir == INPUT) 1251 perr(10, "Input tape not made by volcopy\n"); 1252 mklabel(); 1253 strncpy(V_labl.v_volume, f_p->f_vol_p, 6); 1254 Osup.fs_time = 0; 1255 } else if (new_style) { 1256 Eomflg = (dir == INPUT) ? 1 : Eomflg; 1257 if (!Eomflg) 1258 strncpy(V_labl.v_magic, "Volcopy", 7); 1259 } 1260 } 1261 if (*f_p->f_vol_p == '-') 1262 strncpy(f_p->f_vol_p, V_labl.v_volume, 6); 1263 else if (NOT_EQ(V_labl.v_volume, f_p->f_vol_p, 6)) { 1264 prompt(1, "Header volume(%.6s) does not match (%s)\n", 1265 V_labl.v_volume, f_p->f_vol_p); 1266 strncpy(V_labl.v_volume, f_p->f_vol_p, 6); 1267 } 1268 if (dir == INPUT) { 1269 Bpi = V_labl.v_dens; 1270 if (!Eomflg) { 1271 R_len = V_labl.v_length; 1272 R_num = V_labl.v_reels; 1273 } 1274 if (M3b15) { 1275 if (V_labl.v_type == T_TYPE) { 1276 if (V_labl.v_nblocks == 0) { 1277 Blk_cnt = 10; 1278 Drive_typ = C_DRIVE; 1279 } else 1280 Blk_cnt = V_labl.v_nblocks; 1281 if (V_labl.v_nblocks == 32) 1282 Drive_typ = A_DRIVE; 1283 else 1284 Drive_typ = 0; 1285 } else { 1286 Drive_typ = 0; 1287 Blk_cnt = 10; 1288 Drive_typ = C_DRIVE; 1289 } 1290 } 1291 } 1292 while (!Eomflg && (R_len <= 0 || R_len > 3600)) { 1293 (void) printf(gettext( 1294 "Enter size of reel in feet for <%s>: "), 1295 f_p->f_vol_p); 1296 fgets(resp, 10, Devtty); 1297 R_len = atoi(resp); 1298 if (R_len > 0 && R_len <= 3600) 1299 break; 1300 perr(0, "Size of reel must be > 0, <= 3600\n"); 1301 } 1302 while (!Eomflg && again) { 1303 again = 0; 1304 if (!Bpi) { 1305 (void) printf(gettext( 1306 "Tape density? (i.e., 800 | 1600 | 6250)? ")); 1307 fgets(resp, 10, Devtty); 1308 Bpi = getbpi(resp); 1309 } 1310 switch (Bpi) { 1311 case 800: 1312 R_blks = Ft800x10 * R_len; 1313 break; 1314 case 1600: 1315 if (M3b15) { 1316 switch (Blk_cnt) { 1317 case 1: /* Writing a new tape */ 1318 if (Drive_typ == A_DRIVE) 1319 R_blks = Ft1600x32 * R_len; 1320 else if (Drive_typ == C_DRIVE) 1321 R_blks = Ft1600x10 * R_len; 1322 else 1323 R_blks = Ft1600x16 * R_len; 1324 break; 1325 case 10: 1326 R_blks = Ft1600x10 * R_len; 1327 break; 1328 case 16: 1329 R_blks = Ft1600x16 * R_len; 1330 break; 1331 case 32: 1332 R_blks = Ft1600x32 * R_len; 1333 break; 1334 default: 1335 if (Blk_cnt < 32) 1336 R_blks = blks_per_ft(0.85); 1337 else 1338 R_blks = blks_per_ft(0.88); 1339 R_blks *= R_len; 1340 } /* Blk_cnt */ 1341 } else 1342 R_blks = Ft1600x10 * R_len; 1343 break; 1344 case 6250: 1345 if (M3b15) { 1346 switch (Blk_cnt) { 1347 case 1: /* Writing a new tape */ 1348 if (Drive_typ == A_DRIVE) 1349 R_blks = Ft6250x32 * R_len; 1350 else if (Drive_typ == C_DRIVE) 1351 R_blks = Ft6250x10 * R_len; 1352 else 1353 R_blks = Ft6250x16 * R_len; 1354 break; 1355 case 10: 1356 R_blks = Ft6250x10 * R_len; 1357 break; 1358 case 16: 1359 R_blks = Ft6250x16 * R_len; 1360 break; 1361 case 32: 1362 R_blks = Ft6250x32 * R_len; 1363 break; 1364 default: 1365 if (Blk_cnt < 32) 1366 R_blks = blks_per_ft(0.85); 1367 else 1368 R_blks = blks_per_ft(0.88); 1369 R_blks *= R_len; 1370 } 1371 } else 1372 R_blks = Ft6250x50 * R_len; 1373 break; 1374 default: 1375 perr(0, "Bpi must be 800, 1600, or 6250\n"); 1376 Bpi = 0; 1377 again = 1; 1378 } /* Bpi */ 1379 } /* again */ 1380 (void) printf(gettext("\nReel %.6s"), V_labl.v_volume); 1381 if (!Eomflg) { 1382 V_labl.v_length = R_len; 1383 V_labl.v_dens = Bpi; 1384 (void) printf(gettext(", %d feet, %d BPI\n"), R_len, Bpi); 1385 } else 1386 (void) printf(gettext(", ? feet\n")); 1387 return (1); 1388 } 1389 1390 /* 1391 * hdrck: Look for and validate a volcopy style tape label. 1392 */ 1393 1394 hdrck(dev, fd, tvol) 1395 register int dev, fd; 1396 register char *tvol; 1397 { 1398 register int verify; 1399 struct volcopy_label tlabl; 1400 1401 alarm(15); /* don't scan whole tape for label */ 1402 errno = 0; 1403 if (g_read(dev, fd, &tlabl, sizeof (tlabl)) != sizeof (tlabl)) { 1404 alarm(0); 1405 verify = Otape; 1406 prompt(verify, "Cannot read header\n"); 1407 if (Itape) 1408 close(fd); 1409 else 1410 strncpy(V_labl.v_volume, tvol, 6); 1411 return (verify); 1412 } 1413 alarm(0); 1414 V_labl.v_reel = tlabl.v_reel; 1415 if (NOT_EQ(tlabl.v_volume, tvol, 6)) { 1416 perr(0, "Volume is <%.6s>, not <%s>.\n", tlabl.v_volume, tvol); 1417 if (ask("Want to override? ")) { 1418 if (Otape) 1419 strncpy(V_labl.v_volume, tvol, 6); 1420 else 1421 strncpy(tvol, tlabl.v_volume, 6); 1422 return (1); 1423 } 1424 return (0); 1425 } 1426 return (1); 1427 } 1428 1429 /* 1430 * mklabel: Zero out and initialize a volcopy label. 1431 */ 1432 1433 mklabel() 1434 { 1435 1436 (void) memcpy(&V_labl, Empty, sizeof (V_labl)); 1437 if (!Eomflg) 1438 (void) strcpy(V_labl.v_magic, "Volcopy"); 1439 else 1440 (void) strcpy(V_labl.v_magic, "VOLCOPY"); 1441 } 1442 1443 /* 1444 * rprt: Report activity to user. 1445 */ 1446 1447 rprt() 1448 { 1449 1450 if (Itape) 1451 (void) printf(gettext("\nReading ")); 1452 else /* Otape */ 1453 (void) printf(gettext("\nWriting ")); 1454 if (!Eomflg) 1455 (void) printf(gettext( 1456 "REEL %d of %d VOL = %.6s\n"), 1457 R_cur, R_num, In.f_vol_p); 1458 else 1459 (void) printf(gettext( 1460 "REEL %d of ? VOL = %.6s\n"), R_cur, In.f_vol_p); 1461 } 1462 1463 #ifdef LOG 1464 /* 1465 * fslog: Log current activity. 1466 */ 1467 1468 fslog() 1469 { 1470 FILE *fp = NULL; 1471 1472 fp = fopen("/var/adm/filesave.log", "a"); 1473 if (fp == NULL) { 1474 perr(1, "volcopy: cannot open /var/adm/filesave.log\n"); 1475 } 1476 1477 fprintf(fp, "%s%c%.6s%c%.6s -> %s%c%.6s%c%.6s on %.24s\n", 1478 In.f_dev_p, ';', Ifname, ';', Ifpack, Out.f_dev_p, 1479 ';', Ofname, ';', Ofpack, ctime(&Tvec)); 1480 fclose(fp); 1481 exit(0); 1482 } 1483 #endif /* LOG */ 1484 1485 /* 1486 * getname: Get device name. 1487 */ 1488 1489 getname(nam_p) 1490 register char *nam_p; 1491 { 1492 register int lastchar; 1493 char nam_buf[21]; 1494 1495 nam_buf[0] = '\0'; 1496 (void) printf(gettext("Changing drives? (type RETURN for no,\n")); 1497 (void) printf(gettext("\t`/dev/rmt/??\' or `/dev/rtp/??\' for yes: ")); 1498 fgets(nam_buf, 20, Devtty); 1499 nam_buf[20] = '\0'; 1500 lastchar = strlen(nam_buf) - 1; 1501 if (nam_buf[lastchar] == '\n') 1502 nam_buf[lastchar] = '\0'; /* remove it */ 1503 if (nam_buf[0] != '\0') 1504 (void) strcpy(nam_p, nam_buf); 1505 } 1506 1507 /* 1508 * chgreel: Change reel on end-of-media. 1509 */ 1510 1511 chgreel(f_p, dir) 1512 register struct file_info *f_p; 1513 register int dir; 1514 { 1515 register int again = 1, lastchar, temp; 1516 char vol_tmp[11]; 1517 1518 R_cur++; 1519 while (again) { 1520 again = 0; 1521 errno = 0; 1522 (void) close(f_p->f_des); 1523 (void) getname(f_p->f_dev_p); 1524 (void) printf(gettext( 1525 "Mount tape %d\nType volume-ID when ready: "), R_cur); 1526 vol_tmp[0] = '\0'; 1527 fgets(vol_tmp, 10, Devtty); 1528 vol_tmp[10] = '\0'; 1529 lastchar = strlen(vol_tmp) - 1; 1530 if (vol_tmp[lastchar] == '\n') 1531 vol_tmp[lastchar] = '\0'; /* remove it */ 1532 if (vol_tmp[0] != '\0') { /* if null string, use old vol-id */ 1533 strncpy(f_p->f_vol_p, vol_tmp, 6); 1534 strncpy(V_labl.v_volume, vol_tmp, 6); 1535 } 1536 errno = 0; 1537 f_p->f_des = open(f_p->f_dev_p, 0); 1538 if (f_p->f_des <= 0 || f_p->f_des > 10) { 1539 if (dir == INPUT) 1540 perror("input ERR"); 1541 else 1542 perror("output ERR"); 1543 } 1544 errno = 0; 1545 if (g_init(&(f_p->f_dev), &(f_p->f_des)) < 0) 1546 perr(0, "Initialization error %d\n", errno); 1547 if ((f_p->f_dev != G_TM_TAPE) && (f_p->f_dev != G_XT_TAPE) && 1548 (f_p->f_dev != G_ST_TAPE)) { 1549 (void) printf(gettext( 1550 "\n'%s' is not a valid device"), f_p->f_dev_p); 1551 (void) printf(gettext( 1552 "\n\tenter device name `/dev/rmt/??\' or `/dev/rtp/??\' :")); 1553 again = 1; 1554 continue; 1555 } 1556 if (!hdrck(f_p->f_dev, f_p->f_des, f_p->f_vol_p)) { 1557 again = 1; 1558 continue; 1559 } 1560 switch (dir) { 1561 case INPUT: 1562 if (V_labl.v_reel != R_cur) { 1563 perr(0, "Need reel %d, label says reel %d\n", 1564 R_cur, V_labl.v_reel); 1565 again = 1; 1566 continue; 1567 } 1568 break; 1569 case OUTPUT: 1570 V_labl.v_reel = R_cur; 1571 temp = V_labl.v_offset; 1572 V_labl.v_offset /= BUFSIZ; 1573 close(f_p->f_des); 1574 sleep(2); 1575 errno = 0; 1576 f_p->f_des = open(f_p->f_dev_p, 1); 1577 if (f_p->f_des <= 0 || f_p->f_des > 10) 1578 perror("output ERR"); 1579 errno = 0; 1580 if (g_init(&(f_p->f_dev), &(f_p->f_des)) < 0) 1581 perr(1, "Initialization error %d\n", errno); 1582 errno = 0; 1583 if (g_write(f_p->f_dev, f_p->f_des, &V_labl, 1584 sizeof (V_labl)) < 0) { 1585 perr(0, "Cannot re-write header -Try again!\n"); 1586 again = 1; 1587 V_labl.v_offset = temp; 1588 continue; 1589 } 1590 V_labl.v_offset = temp; 1591 break; 1592 default: 1593 perr(1, "Impossible case\n"); 1594 } /* dir */ 1595 } /* again */ 1596 rprt(); 1597 } 1598 1599 /* 1600 * perr: Print error messages. 1601 */ 1602 1603 static void 1604 perr(int severity, const char *fmt, ...) 1605 { 1606 va_list ap; 1607 1608 va_start(ap, fmt); 1609 (void) fflush(stdout); 1610 (void) fflush(stderr); 1611 if (severity == 10) { 1612 (void) vfprintf(stdout, gettext(fmt), ap); 1613 (void) fprintf(stdout, gettext( 1614 "\t%d reel(s) completed\n"), --R_cur); 1615 (void) fflush(stdout); 1616 (void) fflush(stderr); 1617 cleanup(); 1618 exit(31+9); 1619 } 1620 (void) vfprintf(stderr, gettext(fmt), ap); 1621 (void) fflush(stderr); 1622 va_end(ap); 1623 if (severity > 0) { 1624 (void) cleanup(); 1625 exit(31+severity); 1626 } 1627 } 1628 1629 1630 static void 1631 getinfs(dev, fd, buf) 1632 int dev; 1633 int fd; 1634 char *buf; 1635 { 1636 int cnt; 1637 int i; 1638 1639 if (lseek(fd, SBLOCK * DEV_BSIZE, 0) != SBLOCK * DEV_BSIZE) { 1640 perr(10, "Unable to lseek on input\n"); 1641 } 1642 cnt = SBSIZE/DEV_BSIZE; 1643 for (i = 0; i < cnt; i++) { 1644 if (g_read(dev, fd, (char *)buf + i*DEV_BSIZE, DEV_BSIZE) 1645 != DEV_BSIZE) { 1646 perr(10, "Unable to read on input\n"); 1647 } 1648 } 1649 } 1650 1651 static void 1652 getoutfs(dev, fd, buf, verify) 1653 int dev; 1654 int fd; 1655 char *buf; 1656 int verify; 1657 { 1658 int cnt; 1659 int i; 1660 1661 errno = 0; 1662 if (lseek(fd, SBLOCK * DEV_BSIZE, 0) != SBLOCK * DEV_BSIZE) { 1663 prompt(verify, "Unable to lseek on output\n", errno); 1664 } 1665 cnt = SBSIZE/DEV_BSIZE; 1666 for (i = 0; i < cnt; i++) { 1667 if (g_read(dev, fd, (char *)buf + i*DEV_BSIZE, DEV_BSIZE) 1668 != DEV_BSIZE) { 1669 prompt(verify, "Unable to read on output\n", errno); 1670 } 1671 } 1672 } 1673 1674 static char * 1675 getfslabel(sb) 1676 struct fs *sb; 1677 { 1678 int i; 1679 int blk; 1680 1681 /* 1682 * is there room for label? 1683 */ 1684 1685 if (sb->fs_cpc <= 0) 1686 return (nolabel); 1687 1688 /* 1689 * calculate the available blocks for each rotational position 1690 */ 1691 blk = sb->fs_spc * sb->fs_cpc / sb->fs_nspf; 1692 for (i = 0; i < blk; i += sb->fs_frag) 1693 /* void */; 1694 i -= sb->fs_frag; 1695 blk = i / sb->fs_frag; 1696 1697 return ((char *)&(fs_rotbl(sb)[blk])); 1698 } 1699 1700 static char * 1701 getvolabel(sb) 1702 struct fs *sb; 1703 { 1704 char *p; 1705 int i; 1706 1707 p = getfslabel(sb); 1708 1709 if (p == nolabel || p == NULL) 1710 return (nolabel); 1711 1712 for (i = 0; *p && i < 6; p++, i++) 1713 ; 1714 p++; 1715 return (p); 1716 } 1717