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 2004 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 (!(st_buf.st_mode & S_IFCHR) && !(st_buf.st_mode & S_IFBLK)) { 195 if (st_buf.st_mode & S_IFIFO) 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 == MTB_UFS_MAGIC && 431 (Sptr->fs_version > MTB_UFS_VERSION_1 || 432 Sptr->fs_version < MTB_UFS_VERSION_MIN)) 433 perr(10, "Unrecognized version of UFS--get help\n"); 434 435 (void) memcpy(&Isup, Sptr, Sptr->fs_sbsize); 436 Ifname = getfslabel(&Isup); 437 Ifpack = getvolabel(&Isup); 438 Fs = Sptr->fs_size * Sptr->fs_nspf; 439 } /* R_cur == 1 || !Itape */ 440 441 /* read in superblock */ 442 verify = !Otape || (altflg & MINUSS); 443 (void) getoutfs(Out.f_dev, Out.f_des, Sptr, verify); 444 445 if ((Sptr->fs_magic == FS_MAGIC) || (Sptr->fs_magic == MTB_UFS_MAGIC)) { 446 (void) memcpy(&Osup, Sptr, Sptr->fs_sbsize); 447 Ofname = getfslabel(&Osup); 448 Ofpack = getvolabel(&Osup); 449 } else { 450 int i; 451 452 /* out vol does not contain a ufs file system */ 453 /* stuff let over from Isup */ 454 (void) memcpy(&Osup, &Isup, Isup.fs_sbsize); 455 Ofname = getfslabel(&Osup); 456 Ofpack = getvolabel(&Osup); 457 /* wipe out the fs name and pack name for warning purposes */ 458 for (i = 0; i < 6; i++) Ofname[i] = ' '; 459 for (i = 0; i < 6; i++) Ofpack[i] = ' '; 460 } 461 462 if (Itape) { 463 if (R_cur != 1) { 464 (void) printf(gettext( 465 "\nvolcopy: IF REEL 1 HAS NOT BEEN RESTORED,")); 466 (void) printf(gettext( 467 " STOP NOW AND START OVER ***\07\n")); 468 if (!ask(" Continue? ")) { 469 cleanup(); 470 exit(31+9); 471 } 472 strncpy(Ifname, Fsys_p, 6); 473 strncpy(Ifpack, In.f_vol_p, 6); 474 } 475 if (V_labl.v_reel != R_cur || V_labl.v_reels != R_num) 476 prompt(1, "Tape disagrees: Reel %d of %d : looking for %d of %d\n", 477 V_labl.v_reel, V_labl.v_reels, R_cur, R_num); 478 } else if (Otape) { 479 strncpy(V_labl.v_volume, Out.f_vol_p, 6); 480 strncpy(Ofpack, Out.f_vol_p, 6); 481 strncpy(Ofname, Fsys_p, 6); 482 if (!Eomflg) { 483 R_num = Fs / R_blks + ((Fs % R_blks) ? 1 : 0); 484 (void) printf(gettext( 485 "You will need %d reels.\n"), R_num); 486 (void) printf(gettext( 487 "(\tThe same size and density is expected for all reels)\n")); 488 } 489 } 490 if (NOT_EQ(Fsys_p, Ifname, 6)) { 491 verify = !Otape || (altflg & MINUSS); 492 prompt(verify, 493 "arg. (%.6s) doesn't agree with from fs. (%.6s)\n", 494 Fsys_p, Ifname); 495 } 496 if (NOT_EQ(In.f_vol_p, "-", 6) && NOT_EQ(In.f_vol_p, Ifpack, 6)) { 497 verify = !Otape || (altflg & MINUSS); 498 prompt(verify, "arg. (%.6s) doesn't agree with from vol.(%.6s)\n", 499 In.f_vol_p, Ifpack); 500 } 501 502 if (*In.f_vol_p == '-') 503 In.f_vol_p = Ifpack; 504 if (*Out.f_vol_p == '-') 505 Out.f_vol_p = Ofpack; 506 507 if (R_cur == 1 && (Osup.fs_time + _2_DAYS) > Isup.fs_time) { 508 time_t t; 509 510 verify = altflg & MINUSS; 511 t = (time_t)Osup.fs_time; 512 prompt(verify, "%s less than 48 hours older than %s\n" 513 "To filesystem dated: %s", 514 Out.f_dev_p, In.f_dev_p, ctime(&t)); 515 } 516 if (NOT_EQ(Out.f_vol_p, Ofpack, 6)) { 517 prompt(1, "arg.(%.6s) doesn't agree with to vol.(%.6s)\n", 518 Out.f_vol_p, Ofpack); 519 strncpy(Ofpack, Out.f_vol_p, 6); 520 } 521 if (Isup.fs_size > Osup.fs_size && !Otape) 522 prompt(1, "from fs larger than to fs\n"); 523 if (!Otape && NOT_EQ(Ifname, Ofname, 6)) { 524 verify = altflg & MINUSS; 525 prompt(verify, "warning! from fs(%.6s) differs from to fs(%.6s)\n", 526 Ifname, Ofname); 527 } 528 529 (void) printf(gettext("From: %s, to: %s? "), In.f_dev_p, Out.f_dev_p); 530 if (!(altflg & MINUSA)) { 531 (void) printf(gettext("(DEL if wrong)\n")); 532 sleep(10); 533 } else if (!ask("(y or n) ")) 534 perr(10, "\nvolcopy: STOP\n"); 535 close(In.f_des); 536 close(Out.f_des); 537 sync(); 538 In.f_des = open(In.f_dev_p, O_RDONLY); 539 Out.f_des = open(Out.f_dev_p, O_WRONLY); 540 errno = 0; 541 if (g_init(&In.f_dev, &In.f_des) < 0 || 542 g_init(&Out.f_dev, &Out.f_des) < 0) 543 perr(1, "volcopy: Error %d during initialization\n", errno); 544 if (Itape) { 545 errno = 0; 546 if (g_read(In.f_dev, In.f_des, &V_labl, sizeof (V_labl)) < 547 sizeof (V_labl)) 548 perr(10, "Error while reading label\n"); 549 } else if (Otape) { 550 V_labl.v_reels = R_num; 551 V_labl.v_reel = R_cur; 552 V_labl.v_time = Tvec; 553 V_labl.v_reelblks = R_blks; 554 V_labl.v_blksize = BLKSIZ * Blk_cnt; 555 V_labl.v_nblocks = Blk_cnt; 556 V_labl.v_offset = 0L; 557 V_labl.v_type = T_TYPE; 558 errno = 0; 559 if (g_write(Out.f_dev, Out.f_des, &V_labl, sizeof (V_labl)) < 560 sizeof (V_labl)) 561 perr(10, "Error while writing label\n"); 562 } 563 if (R_cur > 1) { 564 if (!Eomflg) { 565 Fs = (R_cur - 1) * actual_blocks(); 566 lfdes = Otape ? In.f_des : Out.f_des; 567 dist = (long)(Fs * BLKSIZ); 568 } else { /* Eomflg */ 569 if (Otape) 570 perr(1, "Cannot use -reel with -e when copying to tape\n"); 571 lfdes = Out.f_des; 572 dist = (long)(V_labl.v_offset * BLKSIZ); 573 Fs = V_labl.v_offset; 574 } 575 if (lseek(lfdes, dist, 0) < 0) 576 perr(1, "Cannot lseek()\n"); 577 Sptr = Otape ? &Isup : &Osup; 578 if ((Sptr -> fs_magic != FS_MAGIC) && 579 (Sptr -> fs_magic != MTB_UFS_MAGIC)) 580 perr(10, "File System type unknown--get help!\n"); 581 582 if (Sptr->fs_magic == MTB_UFS_MAGIC && 583 (Sptr->fs_version > MTB_UFS_VERSION_1 || 584 Sptr->fs_version < MTB_UFS_VERSION_MIN)) 585 perr(10, "Unrecognized version of UFS--get help\n"); 586 587 Fs = (Sptr->fs_size * Sptr->fs_nspf) - Fs; 588 } 589 if (Itape || Otape) 590 rprt(); 591 592 if (Ipc) { 593 parent_copy(); 594 (void) cleanup(); 595 } else 596 copy(); 597 (void) printf(gettext(" END: %ld blocks.\n"), Blocks); 598 599 #ifdef LOG 600 fslog(); 601 #endif 602 if (Blocks) 603 exit(0); 604 exit(31+1); /* failed.. 0 blocks */ 605 } 606 607 /* 608 * sigalrm: catch alarm signals. 609 */ 610 611 void 612 sigalrm() 613 { 614 void (*signal())(); 615 616 (void) signal(SIGALRM, sigalrm); 617 } 618 619 /* 620 * sigsys: catch illegal system calls to determine if IPC is available. 621 */ 622 623 void 624 sigsys() 625 { 626 627 Ipc = 0; 628 } 629 630 /* 631 * sigint: catch interrupts and prompt user for shell or to quit. 632 */ 633 634 void 635 sigint() 636 { 637 void (*signal())(); 638 extern char **environ; 639 register int tmpflg, i = 0, ps1 = -1, ps2 = -1; 640 641 tmpflg = Yesflg; /* override yesflag for duration of interrupt */ 642 Yesflg = 0; 643 if (Shell_esc && ask("Want Shell? ")) { 644 if (!fork()) { 645 /* both PS1 and PS2 must be exported */ 646 while (environ[i]) { 647 if (EQ(environ[i], "PS1", 3)) 648 ps1 = i; 649 if (EQ(environ[i], "PS2", 3)) 650 ps2 = i; 651 i++; 652 } 653 if (ps1 >= 0 && ps2 >= 0) 654 environ[ps1] = environ[ps2]; 655 (void) signal(SIGINT, SIG_DFL); 656 execl("/usr/bin/sh", "/usr/bin/sh", 0); 657 } else { /* parent */ 658 (void) signal(SIGINT, SIG_IGN); 659 wait((int *)0); 660 } 661 } else if (ask("Want to quit? ")) { 662 if (Pid > 0) 663 kill(Pid, 9); 664 (void) cleanup(); /* ipc */ 665 exit(31+2); 666 } 667 (void) signal(SIGINT, sigint); 668 Yesflg = tmpflg; /* reset Yesflg */ 669 } 670 671 /* 672 * actual_blocks: Calculate the actual number of blocks written to 673 * the tape (will differ from V_labl.v_reelblks if v_reelblks is not 674 * an even multiple of the blocking factor Blk_cnt). 675 */ 676 677 int 678 actual_blocks() 679 { 680 681 if (R_blks % Blk_cnt) 682 return (((R_blks / Blk_cnt) + 1) * Blk_cnt); 683 else 684 return (R_blks); 685 } 686 687 /* 688 * get_mach_type: Determine what machine this is executing on. 689 */ 690 691 int 692 get_mach_type() 693 { 694 struct utsname utsinfo; 695 696 errno = 0; 697 if (uname(&utsinfo) < 0) 698 perr(1, "Unable to determine machine type\n"); 699 if (strcmp(utsinfo.machine, "3B2") == 0) 700 M3b2 = 1; 701 else if (strcmp(utsinfo.machine, "3B15") == 0) 702 M3b15 = 1; 703 } 704 705 /* 706 * mem_setup: Determine memory needs and check for IPC. If IPC is available, 707 * used shared memory and semaphores to increase performance. If no IPC, 708 * get normal memory and only use one process. 709 */ 710 711 int 712 mem_setup() 713 { 714 void (*signal())(); 715 register int cnt, num, size; 716 char *align(); 717 718 union semun { 719 int val; 720 struct semid_ds *buf; 721 ushort_t *array; 722 } sem_arg; 723 724 if (Blk_cnt == 1) { 725 switch (Drive_typ) { 726 case A_DRIVE: 727 Blk_cnt = 32; 728 break; 729 case C_DRIVE: 730 Blk_cnt = 10; 731 break; 732 case K_DRIVE: 733 Blk_cnt = 4; 734 break; 735 case T_DRIVE: 736 if (Bpi == 6250) 737 Blk_cnt = 50; 738 else 739 Blk_cnt = 10; 740 break; 741 default: 742 if (M3b15) { 743 if (Itape || Otape) 744 Blk_cnt = 16; 745 } else { 746 if (Otape || Itape) { 747 if (Bpi == 6250) 748 Blk_cnt = 50; 749 else 750 Blk_cnt = 10; 751 } 752 } 753 break; 754 } /* Drive_typ */ 755 } /* Blk_cnt == 1 */ 756 if (Blk_cnt > 1) /* user overrode g_init */ 757 In.f_bsize = Out.f_bsize = Blk_cnt * BLKSIZ; 758 In.f_bsize = (!Itape) ? Disk_cnt * In.f_bsize : In.f_bsize; 759 Out.f_bsize = (!Otape) ? Disk_cnt * Out.f_bsize : Out.f_bsize; 760 Bufsz = find_lcm(In.f_bsize, Out.f_bsize); 761 num = _128K / (Bufsz + sizeof (int)); 762 Bufsz *= num; 763 size = Bufsz + sizeof (int); 764 /* test to see if ipc is available, the shmat should fail with EINVAL */ 765 (void) signal(SIGSYS, sigsys); 766 errno = 0; 767 if (Ipc) { 768 if ((int)shmat(0, (char *)NULL, 0) < 0 && errno != EINVAL) 769 Ipc = 0; /* something went wrong */ 770 } 771 if (Ipc) { /* ipc is available */ 772 Bufcnt = 2; 773 sem_arg.val = 0; 774 for (cnt = 0; cnt < BUFCNT; cnt++) { 775 errno = 0; 776 if ((Sem_id[cnt] = semget(IPC_PRIVATE, 1, 0)) < 0) 777 perr(1, "Error allocating semaphores: %d", 778 errno); 779 if (semctl(Sem_id[cnt], 0, SETVAL, sem_arg) < 0) 780 perr(1, "Error setting semaphores: %d", errno); 781 if ((Shm_id[cnt] = shmget(IPC_PRIVATE, size, 0)) < 0) 782 perr(1, "Error allocating shared memory: %d", 783 errno); 784 if ((Buf[cnt] = shmat(Shm_id[cnt], 0, 0)) == (void *)-1) 785 perr(1, "Error attaching shared memory: %d", 786 errno); 787 if (shmctl(Shm_id[cnt], SHM_LOCK, 0) < 0) 788 perr(0, "Error locking in shared memory: %d", 789 errno); 790 Cnts[cnt] = (int *)(Buf[cnt] + Bufsz); 791 } 792 } else { /* ipc is not available */ 793 Bufcnt = 1; 794 if ((Buf[0] = align(size)) == (char *)NULL) 795 perr(1, "Out of memory\n"); 796 Cnts[0] = (int *)(Buf[0] + Bufsz); 797 *Cnts[0] = 0; 798 } 799 } 800 801 /* 802 * prompt: Prompt the user for verification. 803 */ 804 805 static void 806 prompt(int verify, const char *fmt, ...) 807 { 808 va_list ap; 809 810 va_start(ap, fmt); 811 if (fmt != NULL) 812 (void) vfprintf(stdout, gettext(fmt), ap); 813 va_end(ap); 814 if (verify) { 815 (void) fprintf(stdout, gettext("Type 'y' to override: ")); 816 if (!ask("")) { 817 cleanup(); 818 exit(31+9); 819 } 820 } 821 } 822 823 /* 824 * ask: Ask the user a question and get the answer. 825 */ 826 827 ask(s) 828 char *s; 829 { 830 char ans[12]; 831 832 (void) printf(gettext(s)); 833 if (Yesflg) { 834 (void) printf(gettext("YES\n")); 835 return (1); 836 } 837 ans[0] = '\0'; 838 fgets(ans, 10, Devtty); 839 for (;;) { 840 switch (ans[0]) { 841 case 'a': 842 case 'A': 843 if (Pid > 0) /* parent with a child */ 844 kill(Pid, 9); 845 cleanup(); 846 exit(31+1); 847 case 'y': 848 case 'Y': 849 return (1); 850 case 'n': 851 case 'N': 852 return (0); 853 default: 854 (void) printf(gettext("\n(y or n)?")); 855 fgets(ans, 10, Devtty); 856 } 857 } 858 } 859 860 /* 861 * align: Align a malloc'd memory section on a page boundry. 862 */ 863 864 char * 865 align(size) 866 register int size; 867 { 868 register int pad; 869 870 if ((pad = ((int)malloc(0) & (PAGESIZE-1))) > 0) { 871 pad = PAGESIZE - pad; 872 if (malloc(pad) == (char *)NULL) 873 return ((char *)NULL); 874 } 875 return (malloc((unsigned)size)); 876 } 877 878 /* 879 * child_copy: Using IPC, this child process reads from shared memory 880 * and writes to the destination file system. 881 */ 882 883 int 884 child_copy() 885 { 886 register int rv, cur_buf, left, have, tpcnt; 887 register char *c_p; 888 889 (void) signal(SIGINT, SIG_IGN); 890 Sem_buf.sem_op = -1; 891 (void) close(In.f_des); 892 if (Otape && !Eomflg) 893 tpcnt = actual_blocks() * BLKSIZ; 894 cur_buf = 0; 895 for (;;) { 896 if (semop(Sem_id[cur_buf], &Sem_buf, 1) < 0) 897 perr(1, "semaphore operation error %d\n", errno); 898 left = *Cnts[cur_buf]; 899 if (!left) 900 break; 901 c_p = Buf[cur_buf]; 902 rv = 0; 903 while (left) { 904 have = (left < Out.f_bsize) ? left : Out.f_bsize; 905 if (!Eomflg && Otape) { 906 if (!tpcnt) { 907 (void) chgreel(&Out, OUTPUT); 908 tpcnt = actual_blocks() * BLKSIZ; 909 } 910 have = (tpcnt < have) ? tpcnt : have; 911 } 912 errno = 0; 913 if ((rv = g_write(Out.f_dev, Out.f_des, c_p, have)) < 914 0) { 915 if (Eomflg && errno == ENOSPC) { 916 (void) chgreel(&Out, OUTPUT); 917 continue; 918 } else 919 perr(1, "I/O error %d on write\n", 920 errno); 921 } 922 left -= rv; 923 c_p += rv; 924 V_labl.v_offset += rv; 925 if (!Eomflg && Otape) 926 tpcnt -= rv; 927 } 928 if (semop(Sem_id[cur_buf], &Sem_buf, 1) < 0) 929 perr(2, "semaphore operation error %d\n", errno); 930 cur_buf = (cur_buf + 1) % BUFCNT; 931 } 932 exit(0); 933 } 934 935 /* 936 * parent_copy: Using shared memory, the parent process reads fromt the 937 * source file system and writes to shared memory. 938 */ 939 940 int 941 parent_copy() 942 { 943 register int rv, left, have, tpcnt, cur_buf; 944 register char *c_p; 945 int eom = 0, xfer_cnt = Fs * BLKSIZ; 946 947 Sem_buf.sem_num = 0; 948 Sem_buf.sem_flg = 0; 949 if ((Pid = fork()) == 0) 950 child_copy(); /* child does not return */ 951 (void) close(Out.f_des); 952 Rstsem_buf.sem_num = 0; 953 Rstsem_buf.sem_flg = 0; 954 Rstsem_buf.sem_op = 2; 955 Sem_buf.sem_op = 0; 956 cur_buf = 0; 957 if (Itape && !Eomflg) 958 tpcnt = actual_blocks() * BLKSIZ; 959 while (xfer_cnt) { 960 if (semop(Sem_id[cur_buf], &Sem_buf, 1) < 0) 961 perr(1, "Semaphore operation error %d\n", errno); 962 c_p = Buf[cur_buf]; 963 left = Bufsz; 964 rv = 0; 965 while (left >= In.f_bsize && xfer_cnt) { 966 have = (xfer_cnt < In.f_bsize) ? xfer_cnt : In.f_bsize; 967 if (!Eomflg && Itape) { 968 if (!tpcnt) { 969 *Cnts[cur_buf] = Bufsz - left; 970 (void) flush_bufs(cur_buf); 971 (void) chgreel(&In, INPUT); 972 tpcnt = actual_blocks() * BLKSIZ; 973 cur_buf = (cur_buf == 0) ? 1 : 0; 974 eom = 1; 975 break; 976 } 977 have = (tpcnt < have) ? tpcnt : have; 978 } 979 errno = 0; 980 if ((rv = g_read(In.f_dev, In.f_des, c_p, have)) < 0) { 981 if (Eomflg && errno == ENOSPC) { 982 *Cnts[cur_buf] = Bufsz - left; 983 (void) flush_bufs(cur_buf); 984 (void) chgreel(&In, INPUT); 985 cur_buf = (cur_buf == 0) ? 1 : 0; 986 eom = 1; 987 break; 988 } else 989 perr(1, "I/O error %d on read\n", 990 errno); 991 } 992 left -= rv; 993 c_p += rv; 994 xfer_cnt -= rv; 995 if (!Eomflg && Itape) 996 tpcnt -= rv; 997 } 998 if (eom > 0) { 999 eom = 0; 1000 if (Eomflg) 1001 xfer_cnt -= rv; 1002 else if (Itape) 1003 tpcnt -= rv; 1004 continue; 1005 } 1006 *Cnts[cur_buf] = Bufsz - left; 1007 Blocks += *Cnts[cur_buf]; 1008 if (semop(Sem_id[cur_buf], &Rstsem_buf, 1) < 0) 1009 perr(2, "Semaphore operation error %d\n", errno); 1010 cur_buf = (cur_buf == 0) ? 1 : 0; 1011 } 1012 if (semop(Sem_id[cur_buf], &Sem_buf, 1) < 0) 1013 perr(3, "Semaphore operation error %d\n", errno); 1014 *Cnts[cur_buf] = 0; 1015 if (semop(Sem_id[cur_buf], &Rstsem_buf, 1) < 0) 1016 perr(4, "Semaphore operation error %d\n", errno); 1017 wait((int *)NULL); 1018 Blocks /= BLKSIZ; 1019 } 1020 1021 /* 1022 * copy: Copy without shared memory. The process reads from the source 1023 * filesystem and writes to the destination filesystem. 1024 */ 1025 1026 int 1027 copy() 1028 { 1029 register int rv, left, have, tpcnt = 1, xfer_cnt = Fs * BLKSIZ; 1030 register char *c_p; 1031 1032 if ((Itape || Otape) && !Eomflg) 1033 tpcnt = actual_blocks() * BLKSIZ; 1034 while (xfer_cnt) { 1035 c_p = (char *)(Buf[0] + *Cnts[0]); 1036 left = Bufsz - *Cnts[0]; 1037 rv = 0; 1038 while (left >= In.f_bsize && xfer_cnt) { 1039 have = (xfer_cnt < In.f_bsize) ? xfer_cnt : In.f_bsize; 1040 if (!Eomflg && Itape) { 1041 if (!tpcnt) { 1042 *Cnts[0] = Bufsz - left; 1043 (void) chgreel(&In, INPUT); 1044 tpcnt = actual_blocks() * BLKSIZ; 1045 break; 1046 } 1047 have = (tpcnt < have) ? tpcnt : have; 1048 } 1049 errno = 0; 1050 if ((rv = g_read(In.f_dev, In.f_des, c_p, have)) < 0) { 1051 if (Eomflg && errno == ENOSPC) { 1052 (void) chgreel(&In, INPUT); 1053 break; 1054 } else 1055 perr(1, "I/O error %d on read\n", 1056 errno); 1057 } 1058 left -= rv; 1059 c_p += rv; 1060 xfer_cnt -= rv; 1061 if (!Eomflg && Itape) 1062 tpcnt -= rv; 1063 } /* left >= In.f_bsize && xfer_cnt */ 1064 *Cnts[0] = Bufsz - left; 1065 Blocks += *Cnts[0]; 1066 c_p = Buf[0]; 1067 left = *Cnts[0]; 1068 rv = 0; 1069 while (left >= Out.f_bsize || (left > 0 && !xfer_cnt)) { 1070 have = (left < Out.f_bsize) ? left : Out.f_bsize; 1071 if (!Eomflg && Otape) { 1072 if (!tpcnt) { 1073 (void) chgreel(&Out, OUTPUT); 1074 tpcnt = actual_blocks() * BLKSIZ; 1075 } 1076 have = (tpcnt < have) ? tpcnt : have; 1077 } 1078 errno = 0; 1079 if ((rv = g_write(Out.f_dev, Out.f_des, c_p, have)) < 1080 0) { 1081 if (Eomflg && errno == ENOSPC) { 1082 (void) chgreel(&Out, OUTPUT); 1083 continue; 1084 } else 1085 perr(1, "I/O error %d on write\n", 1086 errno); 1087 } 1088 left -= rv; 1089 c_p += rv; 1090 V_labl.v_offset += rv; 1091 if (!Eomflg && Otape) 1092 tpcnt -= rv; 1093 } /* left >= Out.f_bsize */ 1094 if (left) { 1095 (void) memcpy(Buf[0], c_p, left); 1096 Blocks -= left; 1097 } 1098 *Cnts[0] = left; 1099 } /* xfer_cnt */ 1100 Blocks /= BLKSIZ; 1101 } 1102 1103 /* 1104 * flush_bufs: Permit child to read the remaining data from the 1105 * buffer before prompting user for end-of-media. 1106 */ 1107 1108 int 1109 flush_bufs(buffer) 1110 register int buffer; 1111 { 1112 1113 Blocks += *Cnts[buffer]; 1114 if (semop(Sem_id[buffer], &Rstsem_buf, 1) < 0) 1115 perr(5, "Semaphore operation error %d\n", errno); 1116 if (semop(Sem_id[buffer], &Sem_buf, 1) < 0) 1117 perr(6, "Semaphore operation error %d\n", errno); 1118 } 1119 1120 /* 1121 * cleanup: Clean up shared memory and semaphore resources. 1122 */ 1123 1124 int 1125 cleanup() 1126 { 1127 register int cnt; 1128 1129 if (Ipc) { 1130 for (cnt = 0; cnt < BUFCNT; cnt++) { 1131 (void) semctl(Sem_id[cnt], IPC_RMID, 0); 1132 (void) shmctl(Shm_id[cnt], IPC_RMID, 0); 1133 } 1134 } 1135 } 1136 1137 /* 1138 * find_lcm: Find the lowest common multiple of two numbers. This is used 1139 * to determine the buffer size that should be malloc(3)'d such that the 1140 * input and output data blocks can both fit evenly into the buffer. 1141 */ 1142 1143 int 1144 find_lcm(sz1, sz2) 1145 register int sz1, sz2; 1146 { 1147 register int inc, lcm, small; 1148 1149 if (sz1 < sz2) { 1150 lcm = inc = sz2; 1151 small = sz1; 1152 } else { /* sz1 >= sz2 */ 1153 lcm = inc = sz1; 1154 small = sz2; 1155 } 1156 while (lcm % small != 0) 1157 lcm += inc; 1158 return (lcm); 1159 } 1160 1161 /* 1162 * Determine bpi information from drive names. 1163 */ 1164 1165 getbpi(inp) 1166 register char *inp; 1167 { 1168 1169 /* 1170 * Kludge to recognize Accellerated Tape Controller usage from 1171 * letter 'a' or 'A' following density given by user. 1172 * 1173 * Kludge to recognize 3B15 Compatibility Mode from 1174 * letter 'c' or 'C' following density given by user. 1175 */ 1176 if (M3b15) { 1177 if (inp[4] == 'a' || inp[4] == 'A') { 1178 Drive_typ = A_DRIVE; 1179 inp[4] = '\0'; 1180 } 1181 if (inp[4] == 'c' || inp[4] == 'C') { 1182 Drive_typ = C_DRIVE; 1183 inp[4] = '\0'; 1184 } 1185 } 1186 return (atoi(inp)); 1187 } 1188 1189 /* 1190 * blks_per_ft: Determine the number of blocks per foot of tape. 1191 * Inter-block gap (dgap) is 0.3 in. 1192 */ 1193 1194 int 1195 blks_per_ft(disc) 1196 register double disc; 1197 { 1198 register double dcnt = Blk_cnt, dBpi = Bpi, dsiz = BLKSIZ, dgap = 0.3; 1199 1200 return ((int)(dcnt / (((dcnt * dsiz / dBpi) + dgap) / 12.0) * disc)); 1201 } 1202 1203 /* 1204 * tapeck: Arbitrary block size. Determine the number of physical blocks per 1205 * foot of tape, including the inter-block gap, and the possibility of a short 1206 * tape. Assume the usable portion of a tape is 85% of its length for small 1207 * block sizes and 88% for large block sizes. 1208 */ 1209 1210 tapeck(f_p, dir) 1211 register struct file_info *f_p; 1212 register int dir; 1213 { 1214 register int again = 1, verify, old_style, new_style; 1215 char resp[16]; 1216 1217 errno = 0; 1218 if ((f_p->f_bsize = g_init(&f_p->f_dev, &f_p->f_des)) < 0) 1219 perr(1, "volcopy: Error %d during initialization\n", errno); 1220 if ((f_p->f_dev != G_TM_TAPE) && (f_p->f_dev != G_XT_TAPE) && 1221 (f_p->f_dev != G_ST_TAPE)) 1222 return (0); 1223 V_labl.v_magic[0] = '\0'; /* scribble on old data */ 1224 alarm(5); 1225 if (g_read(f_p->f_dev, f_p->f_des, &V_labl, sizeof (V_labl)) <= 0) { 1226 if (dir == INPUT) 1227 perror("input tape"); 1228 else 1229 perror("output tape"); 1230 } 1231 alarm(0); 1232 if (V_labl.v_reel == (char)NULL && dir == INPUT) 1233 perr(9, "Input tape is empty\n"); 1234 else { 1235 old_style = strncmp(V_labl.v_magic, "Volcopy", 7) == 0; 1236 new_style = strncmp(V_labl.v_magic, "VOLCOPY", 7) == 0; 1237 if (!old_style && !new_style) { 1238 verify = (dir == INPUT) ? 0 : 1; 1239 prompt(verify, "Not a labeled tape\n"); 1240 if (dir == INPUT) 1241 perr(10, "Input tape not made by volcopy\n"); 1242 mklabel(); 1243 strncpy(V_labl.v_volume, f_p->f_vol_p, 6); 1244 Osup.fs_time = 0; 1245 } else if (new_style) { 1246 Eomflg = (dir == INPUT) ? 1 : Eomflg; 1247 if (!Eomflg) 1248 strncpy(V_labl.v_magic, "Volcopy", 7); 1249 } 1250 } 1251 if (*f_p->f_vol_p == '-') 1252 strncpy(f_p->f_vol_p, V_labl.v_volume, 6); 1253 else if (NOT_EQ(V_labl.v_volume, f_p->f_vol_p, 6)) { 1254 prompt(1, "Header volume(%.6s) does not match (%s)\n", 1255 V_labl.v_volume, f_p->f_vol_p); 1256 strncpy(V_labl.v_volume, f_p->f_vol_p, 6); 1257 } 1258 if (dir == INPUT) { 1259 Bpi = V_labl.v_dens; 1260 if (!Eomflg) { 1261 R_len = V_labl.v_length; 1262 R_num = V_labl.v_reels; 1263 } 1264 if (M3b15) { 1265 if (V_labl.v_type == T_TYPE) { 1266 if (V_labl.v_nblocks == 0) { 1267 Blk_cnt = 10; 1268 Drive_typ = C_DRIVE; 1269 } else 1270 Blk_cnt = V_labl.v_nblocks; 1271 if (V_labl.v_nblocks == 32) 1272 Drive_typ = A_DRIVE; 1273 else 1274 Drive_typ = 0; 1275 } else { 1276 Drive_typ = 0; 1277 Blk_cnt = 10; 1278 Drive_typ = C_DRIVE; 1279 } 1280 } 1281 } 1282 while (!Eomflg && (R_len <= 0 || R_len > 3600)) { 1283 (void) printf(gettext( 1284 "Enter size of reel in feet for <%s>: "), 1285 f_p->f_vol_p); 1286 fgets(resp, 10, Devtty); 1287 R_len = atoi(resp); 1288 if (R_len > 0 && R_len <= 3600) 1289 break; 1290 perr(0, "Size of reel must be > 0, <= 3600\n"); 1291 } 1292 while (!Eomflg && again) { 1293 again = 0; 1294 if (!Bpi) { 1295 (void) printf(gettext( 1296 "Tape density? (i.e., 800 | 1600 | 6250)? ")); 1297 fgets(resp, 10, Devtty); 1298 Bpi = getbpi(resp); 1299 } 1300 switch (Bpi) { 1301 case 800: 1302 R_blks = Ft800x10 * R_len; 1303 break; 1304 case 1600: 1305 if (M3b15) { 1306 switch (Blk_cnt) { 1307 case 1: /* Writing a new tape */ 1308 if (Drive_typ == A_DRIVE) 1309 R_blks = Ft1600x32 * R_len; 1310 else if (Drive_typ == C_DRIVE) 1311 R_blks = Ft1600x10 * R_len; 1312 else 1313 R_blks = Ft1600x16 * R_len; 1314 break; 1315 case 10: 1316 R_blks = Ft1600x10 * R_len; 1317 break; 1318 case 16: 1319 R_blks = Ft1600x16 * R_len; 1320 break; 1321 case 32: 1322 R_blks = Ft1600x32 * R_len; 1323 break; 1324 default: 1325 if (Blk_cnt < 32) 1326 R_blks = blks_per_ft(0.85); 1327 else 1328 R_blks = blks_per_ft(0.88); 1329 R_blks *= R_len; 1330 } /* Blk_cnt */ 1331 } else 1332 R_blks = Ft1600x10 * R_len; 1333 break; 1334 case 6250: 1335 if (M3b15) { 1336 switch (Blk_cnt) { 1337 case 1: /* Writing a new tape */ 1338 if (Drive_typ == A_DRIVE) 1339 R_blks = Ft6250x32 * R_len; 1340 else if (Drive_typ == C_DRIVE) 1341 R_blks = Ft6250x10 * R_len; 1342 else 1343 R_blks = Ft6250x16 * R_len; 1344 break; 1345 case 10: 1346 R_blks = Ft6250x10 * R_len; 1347 break; 1348 case 16: 1349 R_blks = Ft6250x16 * R_len; 1350 break; 1351 case 32: 1352 R_blks = Ft6250x32 * R_len; 1353 break; 1354 default: 1355 if (Blk_cnt < 32) 1356 R_blks = blks_per_ft(0.85); 1357 else 1358 R_blks = blks_per_ft(0.88); 1359 R_blks *= R_len; 1360 } 1361 } else 1362 R_blks = Ft6250x50 * R_len; 1363 break; 1364 default: 1365 perr(0, "Bpi must be 800, 1600, or 6250\n"); 1366 Bpi = 0; 1367 again = 1; 1368 } /* Bpi */ 1369 } /* again */ 1370 (void) printf(gettext("\nReel %.6s"), V_labl.v_volume); 1371 if (!Eomflg) { 1372 V_labl.v_length = R_len; 1373 V_labl.v_dens = Bpi; 1374 (void) printf(gettext(", %d feet, %d BPI\n"), R_len, Bpi); 1375 } else 1376 (void) printf(gettext(", ? feet\n")); 1377 return (1); 1378 } 1379 1380 /* 1381 * hdrck: Look for and validate a volcopy style tape label. 1382 */ 1383 1384 hdrck(dev, fd, tvol) 1385 register int dev, fd; 1386 register char *tvol; 1387 { 1388 register int verify; 1389 struct volcopy_label tlabl; 1390 1391 alarm(15); /* don't scan whole tape for label */ 1392 errno = 0; 1393 if (g_read(dev, fd, &tlabl, sizeof (tlabl)) != sizeof (tlabl)) { 1394 alarm(0); 1395 verify = Otape; 1396 prompt(verify, "Cannot read header\n"); 1397 if (Itape) 1398 close(fd); 1399 else 1400 strncpy(V_labl.v_volume, tvol, 6); 1401 return (verify); 1402 } 1403 alarm(0); 1404 V_labl.v_reel = tlabl.v_reel; 1405 if (NOT_EQ(tlabl.v_volume, tvol, 6)) { 1406 perr(0, "Volume is <%.6s>, not <%s>.\n", tlabl.v_volume, tvol); 1407 if (ask("Want to override? ")) { 1408 if (Otape) 1409 strncpy(V_labl.v_volume, tvol, 6); 1410 else 1411 strncpy(tvol, tlabl.v_volume, 6); 1412 return (1); 1413 } 1414 return (0); 1415 } 1416 return (1); 1417 } 1418 1419 /* 1420 * mklabel: Zero out and initialize a volcopy label. 1421 */ 1422 1423 mklabel() 1424 { 1425 1426 (void) memcpy(&V_labl, Empty, sizeof (V_labl)); 1427 if (!Eomflg) 1428 (void) strcpy(V_labl.v_magic, "Volcopy"); 1429 else 1430 (void) strcpy(V_labl.v_magic, "VOLCOPY"); 1431 } 1432 1433 /* 1434 * rprt: Report activity to user. 1435 */ 1436 1437 rprt() 1438 { 1439 1440 if (Itape) 1441 (void) printf(gettext("\nReading ")); 1442 else /* Otape */ 1443 (void) printf(gettext("\nWriting ")); 1444 if (!Eomflg) 1445 (void) printf(gettext( 1446 "REEL %d of %d VOL = %.6s\n"), 1447 R_cur, R_num, In.f_vol_p); 1448 else 1449 (void) printf(gettext( 1450 "REEL %d of ? VOL = %.6s\n"), R_cur, In.f_vol_p); 1451 } 1452 1453 #ifdef LOG 1454 /* 1455 * fslog: Log current activity. 1456 */ 1457 1458 fslog() 1459 { 1460 FILE *fp = NULL; 1461 1462 fp = fopen("/var/adm/filesave.log", "a"); 1463 if (fp == NULL) { 1464 perr(1, "volcopy: cannot open /var/adm/filesave.log\n"); 1465 } 1466 1467 fprintf(fp, "%s%c%.6s%c%.6s -> %s%c%.6s%c%.6s on %.24s\n", 1468 In.f_dev_p, ';', Ifname, ';', Ifpack, Out.f_dev_p, 1469 ';', Ofname, ';', Ofpack, ctime(&Tvec)); 1470 fclose(fp); 1471 exit(0); 1472 } 1473 #endif /* LOG */ 1474 1475 /* 1476 * getname: Get device name. 1477 */ 1478 1479 getname(nam_p) 1480 register char *nam_p; 1481 { 1482 register int lastchar; 1483 char nam_buf[21]; 1484 1485 nam_buf[0] = '\0'; 1486 (void) printf(gettext("Changing drives? (type RETURN for no,\n")); 1487 (void) printf(gettext("\t`/dev/rmt/??\' or `/dev/rtp/??\' for yes: ")); 1488 fgets(nam_buf, 20, Devtty); 1489 nam_buf[20] = '\0'; 1490 lastchar = strlen(nam_buf) - 1; 1491 if (nam_buf[lastchar] == '\n') 1492 nam_buf[lastchar] = '\0'; /* remove it */ 1493 if (nam_buf[0] != '\0') 1494 (void) strcpy(nam_p, nam_buf); 1495 } 1496 1497 /* 1498 * chgreel: Change reel on end-of-media. 1499 */ 1500 1501 chgreel(f_p, dir) 1502 register struct file_info *f_p; 1503 register int dir; 1504 { 1505 register int again = 1, lastchar, temp; 1506 char vol_tmp[11]; 1507 1508 R_cur++; 1509 while (again) { 1510 again = 0; 1511 errno = 0; 1512 (void) close(f_p->f_des); 1513 (void) getname(f_p->f_dev_p); 1514 (void) printf(gettext( 1515 "Mount tape %d\nType volume-ID when ready: "), R_cur); 1516 vol_tmp[0] = '\0'; 1517 fgets(vol_tmp, 10, Devtty); 1518 vol_tmp[10] = '\0'; 1519 lastchar = strlen(vol_tmp) - 1; 1520 if (vol_tmp[lastchar] == '\n') 1521 vol_tmp[lastchar] = '\0'; /* remove it */ 1522 if (vol_tmp[0] != '\0') { /* if null string, use old vol-id */ 1523 strncpy(f_p->f_vol_p, vol_tmp, 6); 1524 strncpy(V_labl.v_volume, vol_tmp, 6); 1525 } 1526 errno = 0; 1527 f_p->f_des = open(f_p->f_dev_p, 0); 1528 if (f_p->f_des <= 0 || f_p->f_des > 10) { 1529 if (dir == INPUT) 1530 perror("input ERR"); 1531 else 1532 perror("output ERR"); 1533 } 1534 errno = 0; 1535 if (g_init(&(f_p->f_dev), &(f_p->f_des)) < 0) 1536 perr(0, "Initialization error %d\n", errno); 1537 if ((f_p->f_dev != G_TM_TAPE) && (f_p->f_dev != G_XT_TAPE) && 1538 (f_p->f_dev != G_ST_TAPE)) { 1539 (void) printf(gettext( 1540 "\n'%s' is not a valid device"), f_p->f_dev_p); 1541 (void) printf(gettext( 1542 "\n\tenter device name `/dev/rmt/??\' or `/dev/rtp/??\' :")); 1543 again = 1; 1544 continue; 1545 } 1546 if (!hdrck(f_p->f_dev, f_p->f_des, f_p->f_vol_p)) { 1547 again = 1; 1548 continue; 1549 } 1550 switch (dir) { 1551 case INPUT: 1552 if (V_labl.v_reel != R_cur) { 1553 perr(0, "Need reel %d, label says reel %d\n", 1554 R_cur, V_labl.v_reel); 1555 again = 1; 1556 continue; 1557 } 1558 break; 1559 case OUTPUT: 1560 V_labl.v_reel = R_cur; 1561 temp = V_labl.v_offset; 1562 V_labl.v_offset /= BUFSIZ; 1563 close(f_p->f_des); 1564 sleep(2); 1565 errno = 0; 1566 f_p->f_des = open(f_p->f_dev_p, 1); 1567 if (f_p->f_des <= 0 || f_p->f_des > 10) 1568 perror("output ERR"); 1569 errno = 0; 1570 if (g_init(&(f_p->f_dev), &(f_p->f_des)) < 0) 1571 perr(1, "Initialization error %d\n", errno); 1572 errno = 0; 1573 if (g_write(f_p->f_dev, f_p->f_des, &V_labl, 1574 sizeof (V_labl)) < 0) { 1575 perr(0, "Cannot re-write header -Try again!\n"); 1576 again = 1; 1577 V_labl.v_offset = temp; 1578 continue; 1579 } 1580 V_labl.v_offset = temp; 1581 break; 1582 default: 1583 perr(1, "Impossible case\n"); 1584 } /* dir */ 1585 } /* again */ 1586 rprt(); 1587 } 1588 1589 /* 1590 * perr: Print error messages. 1591 */ 1592 1593 static void 1594 perr(int severity, const char *fmt, ...) 1595 { 1596 va_list ap; 1597 1598 va_start(ap, fmt); 1599 (void) fflush(stdout); 1600 (void) fflush(stderr); 1601 if (severity == 10) { 1602 (void) vfprintf(stdout, gettext(fmt), ap); 1603 (void) fprintf(stdout, gettext( 1604 "\t%d reel(s) completed\n"), --R_cur); 1605 (void) fflush(stdout); 1606 (void) fflush(stderr); 1607 cleanup(); 1608 exit(31+9); 1609 } 1610 (void) vfprintf(stderr, gettext(fmt), ap); 1611 (void) fflush(stderr); 1612 va_end(ap); 1613 if (severity > 0) { 1614 (void) cleanup(); 1615 exit(31+severity); 1616 } 1617 } 1618 1619 1620 static void 1621 getinfs(dev, fd, buf) 1622 int dev; 1623 int fd; 1624 char *buf; 1625 { 1626 int cnt; 1627 int i; 1628 1629 if (lseek(fd, SBLOCK * DEV_BSIZE, 0) != SBLOCK * DEV_BSIZE) { 1630 perr(10, "Unable to lseek on input\n"); 1631 } 1632 cnt = SBSIZE/DEV_BSIZE; 1633 for (i = 0; i < cnt; i++) { 1634 if (g_read(dev, fd, (char *)buf + i*DEV_BSIZE, DEV_BSIZE) 1635 != DEV_BSIZE) { 1636 perr(10, "Unable to read on input\n"); 1637 } 1638 } 1639 } 1640 1641 static void 1642 getoutfs(dev, fd, buf, verify) 1643 int dev; 1644 int fd; 1645 char *buf; 1646 int verify; 1647 { 1648 int cnt; 1649 int i; 1650 1651 errno = 0; 1652 if (lseek(fd, SBLOCK * DEV_BSIZE, 0) != SBLOCK * DEV_BSIZE) { 1653 prompt(verify, "Unable to lseek on output\n", errno); 1654 } 1655 cnt = SBSIZE/DEV_BSIZE; 1656 for (i = 0; i < cnt; i++) { 1657 if (g_read(dev, fd, (char *)buf + i*DEV_BSIZE, DEV_BSIZE) 1658 != DEV_BSIZE) { 1659 prompt(verify, "Unable to read on output\n", errno); 1660 } 1661 } 1662 } 1663 1664 static char * 1665 getfslabel(sb) 1666 struct fs *sb; 1667 { 1668 int i; 1669 int blk; 1670 1671 /* 1672 * is there room for label? 1673 */ 1674 1675 if (sb->fs_cpc <= 0) 1676 return (nolabel); 1677 1678 /* 1679 * calculate the available blocks for each rotational position 1680 */ 1681 blk = sb->fs_spc * sb->fs_cpc / sb->fs_nspf; 1682 for (i = 0; i < blk; i += sb->fs_frag) 1683 /* void */; 1684 i -= sb->fs_frag; 1685 blk = i / sb->fs_frag; 1686 1687 return ((char *)&(fs_rotbl(sb)[blk])); 1688 } 1689 1690 static char * 1691 getvolabel(sb) 1692 struct fs *sb; 1693 { 1694 char *p; 1695 int i; 1696 1697 p = getfslabel(sb); 1698 1699 if (p == nolabel || p == NULL) 1700 return (nolabel); 1701 1702 for (i = 0; *p && i < 6; p++, i++) 1703 ; 1704 p++; 1705 return (p); 1706 } 1707