4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
39 #include <sys/param.h>
41 #include <sys/types.h>
42 #include <sys/sysmacros.h>
43 #include <sys/vnode.h>
44 #include <sys/fs/ufs_fsdir.h>
45 #include <sys/fs/ufs_inode.h>
46 #include <sys/fs/ufs_fs.h>
48 #include <sys/statvfs.h>
56 #include <sys/errno.h>
57 #include <sys/utsname.h>
67 * main I/O information structure, contains information for the
68 * source and destination files.
72 char *f_dev_p
, /* name of device */
73 *f_vol_p
; /* volume name */
74 int f_bsize
, /* size to buffer I/O to */
75 f_des
, /* file descriptor */
76 f_dev
; /* device type (generic I/O library) */
80 int Sem_id
[BUFCNT
], /* semaphore ids for controlling shared memory */
81 Shm_id
[BUFCNT
], /* shared memory identifier */
82 *Cnts
[BUFCNT
]; /* an array of byte counts for shared memory */
84 char Empty
[BLKSIZ
], /* empty memory used to clear sections of memory */
85 *Buf
[BUFCNT
]; /* buffer pointers (possibly to shared memory) */
87 struct sembuf Sem_buf
, /* semaphore operation buffer */
88 Rstsem_buf
; /* semaphore reset operation buffer */
96 sb_un isup
, osup
, tsup
;
98 #define Isup isup.sblk
99 #define Osup osup.sblk
101 struct fs
*Sptr
= (struct fs
*)&tsup
.sblk
; /* super-block pointer */
103 char *Ifname
, *Ifpack
, *Ofname
, *Ofpack
;
104 struct volcopy_label V_labl
;
106 char From_vol
[VVOLLEN
+ 1],
110 static char *nolabel
= ""; /* used when there is no room for label */
112 int Blk_cnt
= 1, /* Do I/O in (Blk_cnt * BLKSIZ) byte blocks */
113 Blocks
= 0, /* Number of blocks transferred */
118 Disk_cnt
= 1, /* Disk I/O (Disk_cnt * Blk_cnt * BLKSIZ) byte blocks */
119 Drive_typ
= 0, /* Flag for special tape drive types */
123 M3b15
= 0, /* Machine types, set to 1 for the machine */
124 M3b2
= 0, /* the command is executing on */
127 R_blks
= 0, /* Number of blocks per tape reel */
128 R_cur
= 1, /* Current tape reel being processed */
129 R_len
= 0, /* Length in feet of tape reels */
130 R_num
= 0, /* Number of tape reels to be processed */
131 Shell_esc
= 1, /* Allow shell after delete -nosh (3b15) can disable */
142 static void getinfs(),
145 static char *getfslabel(struct fs
*);
146 static char *getvolabel(struct fs
*);
147 static void prompt(int, const char *, ...);
148 static void perr(int, const char *, ...);
149 static void mklabel(void);
150 static void get_mach_type(void);
151 static void mem_setup(void);
152 static void rprt(void);
153 static void chgreel(struct file_info
*, int);
154 static void parent_copy(void);
155 static void copy(void);
156 static void flush_bufs(int);
157 static void cleanup(void);
160 static int fslog(void);
164 * g_init(), g_read(), g_write() originally came from libgenIO,
165 * a totally obsolete device interface library, now deleted.
166 * volcopy should be deleted too, since it doesn't work.
169 #define G_TM_TAPE 1 /* Tapemaster controller */
170 #define G_XY_DISK 3 /* xy disks */
171 #define G_SD_DISK 7 /* scsi sd disk */
172 #define G_XT_TAPE 8 /* xt tapes */
173 #define G_SF_FLOPPY 9 /* sf floppy */
174 #define G_XD_DISK 10 /* xd disks */
175 #define G_ST_TAPE 11 /* scsi tape */
176 #define G_NS 12 /* noswap pseudo-dev */
177 #define G_RAM 13 /* ram pseudo-dev */
178 #define G_FT 14 /* tftp */
179 #define G_HD 15 /* 386 network disk */
180 #define G_FD 16 /* 386 AT disk */
181 #define G_FILE 28 /* file, not a device */
182 #define G_NO_DEV 29 /* device does not require special treatment */
183 #define G_DEV_MAX 30 /* last valid device type */
186 * g_init: Determine the device being accessed, set the buffer size,
187 * and perform any device specific initialization. Since at this point
188 * Sun has no system call to read the configuration, the major numbers
189 * are assumed to be static and types are figured out as such. However,
190 * as a rough estimate, the buffer size for all types is set to 512
194 g_init(int *devtype
, int *fdes
)
199 struct statvfs64 stfs_buf
;
202 if (fstat(*fdes
, &st_buf
) == -1)
204 if (!S_ISCHR(st_buf
.st_mode
) && !S_ISBLK(st_buf
.st_mode
)) {
205 if (S_ISFIFO(st_buf
.st_mode
))
208 /* find block size for this file system */
210 if (fstatvfs(*fdes
, &stfs_buf
) < 0) {
214 bufsize
= stfs_buf
.f_bsize
;
224 * g_read: Read nbytes of data from fdes (of type devtype) and place
225 * data in location pointed to by buf. In case of end of medium,
226 * translate (where necessary) device specific EOM indications into
227 * the generic EOM indication of rv = -1, errno = ENOSPC.
231 g_read(int devtype
, int fdes
, void *buf
, size_t nbytes
)
235 rv
= read(fdes
, buf
, nbytes
);
237 /* st devices return 0 when no space left */
238 if ((rv
== 0 && errno
== 0) || (rv
== -1 && errno
== EIO
)) {
247 * g_write: Write nbytes of data to fdes (of type devtype) from
248 * the location pointed to by buf. In case of end of medium,
249 * translate (where necessary) device specific EOM indications into
250 * the generic EOM indication of rv = -1, errno = ENOSPC.
254 g_write(int devtype
, int fdes
, void *buf
, size_t nbytes
)
258 rv
= write(fdes
, buf
, nbytes
);
260 /* st devices return 0 when no more space left */
261 if ((rv
== 0 && errno
== 0) || (rv
== -1 && errno
== EIO
)) {
270 * filesystem copy with propagation of volume ID and filesystem name:
272 * volcopy [-options] filesystem /dev/from From_vol /dev/to To_vol
275 * -feet - length of tape
276 * -bpi - recording density
277 * -reel - reel number (if not starting from beginning)
278 * -buf - use double buffered i/o (if dens >= 1600 bpi)
279 * -block - Set the transfer block size to NUM physical blocks (512
280 * bytes on 3B2 and 3B15). Note that an arbitrary block size might
281 * or might not work on a given system. Also, the block size
282 * read from the header of an input tape silently overrides this.
283 * -nosh - Don't offer the user a shell after hitting break or delete.
284 * -r - Read NUM transfer blocks from the disk at once and write it
285 * to the output device one block at a time. Intended only to
286 * boost the 3B15 EDFC disk to tape performance. Disabled on 3B2.
287 * -a - ask "y or n" instead of "DEL if wrong"
288 * -s - inverse of -a, from/to devices are printed followed by `?'.
289 * User has 10 seconds to DEL if mistaken!
290 * -y - assume "yes" response to all questions
294 * volcopy root /dev/rdsk/0s2 pk5 /dev/rdsk/1s2 pk12
296 * volcopy u3 /dev/rdsk/1s5 pk1 /dev/rmt/0m tp123
298 * volcopy u5 /dev/rmt/0m - /dev/rdsk/1s5 -
302 main(int argc
, char *argv
[])
305 int lfdes
, altflg
= 0, result
, verify
;
308 void sigalrm(), sigint();
312 (void) setlocale(LC_ALL
, "");
313 #if !defined(TEXT_DOMAIN)
314 #define TEXT_DOMAIN "SYS_TEST"
316 (void) textdomain(TEXT_DOMAIN
);
318 (void) get_mach_type();
319 (void) signal(SIGINT
, sigint
);
320 (void) signal(SIGALRM
, sigalrm
);
321 In
.f_bsize
= Out
.f_bsize
= BLKSIZ
;
322 while (argc
> 1 && argv
[1][0] == '-') {
323 if (EQ(argv
[1], "-a", 2)) {
325 } else if (EQ(argv
[1], "-e", 2)) {
327 } else if (EQ(argv
[1], "-s", 2)) {
329 } else if (EQ(argv
[1], "-y", 2)) {
331 } else if (EQ(argv
[1], "-buf", 4)) {
333 } else if (EQ(argv
[1], "-bpi", 4)) {
334 if ((c
= argv
[1][4]) >= '0' && c
<= '9')
335 Bpi
= getbpi(&argv
[1][4]);
339 Bpi
= getbpi(&argv
[1][0]);
341 } else if (EQ(argv
[1], "-feet", 5)) {
342 if ((c
= argv
[1][5]) >= '0' && c
<= '9')
343 R_len
= atoi(&argv
[1][5]);
347 R_len
= atoi(&argv
[1][0]);
349 } else if (EQ(argv
[1], "-reel", 5)) {
350 if ((c
= argv
[1][5]) >= '0' && c
<= '9')
351 R_cur
= atoi(&argv
[1][5]);
355 R_cur
= atoi(&argv
[1][0]);
357 } else if (EQ(argv
[1], "-r", 2)) { /* 3b15 only */
358 if ((c
= argv
[1][2]) >= '0' && c
<= '9')
359 Disk_cnt
= atoi(&argv
[1][2]);
363 Disk_cnt
= atoi(&argv
[1][0]);
366 perr(1, "volcopy: Need a non-zero value for the -r option\n");
367 } else if (EQ(argv
[1], "-block", 6)) { /* 3b15 only */
368 if ((c
= argv
[1][6]) >= '0' && c
<= '9')
369 Blk_cnt
= atoi(&argv
[1][6]);
373 Blk_cnt
= atoi(&argv
[1][0]);
376 perr(1, "volcopy: Need a non-zero value for the -block option\n");
377 } else if (EQ(argv
[1], "-nosh", 5)) { /* 3b15 only */
380 perr(1, "<%s> invalid option\n", argv
[1]);
383 } /* argv[1][0] == '-' */
385 Devtty
= fopen("/dev/tty", "r");
386 if ((Devtty
== NULL
) && !isatty(0))
391 perr(9, "volcopy: -e and -feet are mutually exclusive\n");
392 if ((altflg
& MINUSA
) && (altflg
& MINUSS
))
393 perr(9, "volcopy: -a and -s are mutually exclusive\n");
394 if (argc
!= 6) /* if mandatory fields not present */
395 perr(9, "ufs usage: volcopy [-F ufs] [generic options] \
396 fsname /devfrom volfrom /devto volto\n");
397 if (!(altflg
& MINUSA
)) /* -a was not specified, use default (-s) */
400 In
.f_dev_p
= argv
[DEV_IN
];
401 Out
.f_dev_p
= argv
[DEV_OUT
];
402 strncpy(To_vol
, argv
[VOL_OUT
], VVOLLEN
);
403 To_vol
[VVOLLEN
] = '\0';
404 Out
.f_vol_p
= &To_vol
[0];
405 strncpy(From_vol
, argv
[VOL_IN
], VVOLLEN
);
406 From_vol
[VVOLLEN
] = '\0';
407 In
.f_vol_p
= &From_vol
[0];
408 Fsys_p
= argv
[FIL_SYS
];
410 if ((In
.f_des
= open(In
.f_dev_p
, O_RDONLY
)) < 1)
411 perr(10, "%s: cannot open\n", In
.f_dev_p
);
412 if ((Out
.f_des
= open(Out
.f_dev_p
, O_RDONLY
)) < 1)
413 perr(10, "%s: cannot open\n", Out
.f_dev_p
);
415 if (fstat(In
.f_des
, &stbuf
) < 0 || (stbuf
.st_mode
& S_IFMT
) != S_IFCHR
)
416 perr(10, "From device not character-special\n");
417 if (fstat(Out
.f_des
, &stbuf
) < 0 || (stbuf
.st_mode
& S_IFMT
) != S_IFCHR
)
418 perr(10, "To device not character-special\n");
420 if ((Itape
= tapeck(&In
, INPUT
)) == 1)
421 R_blks
= V_labl
.v_reelblks
;
422 Otape
= tapeck(&Out
, OUTPUT
);
424 perr(10, "Use dd(1) command to copy tapes\n");
427 perr(1, "The -buf option requires ipc\n");
428 if (!Itape
&& !Otape
)
430 if (R_cur
== 1 || !Itape
) {
431 /* read in superblock */
433 (void) getinfs(In
.f_dev
, In
.f_des
, Sptr
);
435 if ((Sptr
->fs_magic
!= FS_MAGIC
) &&
436 (Sptr
->fs_magic
!= MTB_UFS_MAGIC
))
437 perr(10, "File System type unknown--get help\n");
439 if (Sptr
->fs_magic
== FS_MAGIC
&&
440 (Sptr
->fs_version
!= UFS_EFISTYLE4NONEFI_VERSION_2
&&
441 Sptr
->fs_version
!= UFS_VERSION_MIN
))
442 perr(10, "Unrecognized version of UFS--get help\n");
444 if (Sptr
->fs_magic
== MTB_UFS_MAGIC
&&
445 (Sptr
->fs_version
> MTB_UFS_VERSION_1
||
446 Sptr
->fs_version
< MTB_UFS_VERSION_MIN
))
447 perr(10, "Unrecognized version of UFS--get help\n");
449 (void) memcpy(&Isup
, Sptr
, Sptr
->fs_sbsize
);
450 Ifname
= getfslabel(&Isup
);
451 Ifpack
= getvolabel(&Isup
);
452 Fs
= Sptr
->fs_size
* Sptr
->fs_nspf
;
453 } /* R_cur == 1 || !Itape */
455 /* read in superblock */
456 verify
= !Otape
|| (altflg
& MINUSS
);
457 (void) getoutfs(Out
.f_dev
, Out
.f_des
, Sptr
, verify
);
459 if ((Sptr
->fs_magic
== FS_MAGIC
) || (Sptr
->fs_magic
== MTB_UFS_MAGIC
)) {
460 (void) memcpy(&Osup
, Sptr
, Sptr
->fs_sbsize
);
461 Ofname
= getfslabel(&Osup
);
462 Ofpack
= getvolabel(&Osup
);
466 /* out vol does not contain a ufs file system */
467 /* stuff let over from Isup */
468 (void) memcpy(&Osup
, &Isup
, Isup
.fs_sbsize
);
469 Ofname
= getfslabel(&Osup
);
470 Ofpack
= getvolabel(&Osup
);
471 /* wipe out the fs name and pack name for warning purposes */
472 for (i
= 0; i
< 6; i
++) Ofname
[i
] = ' ';
473 for (i
= 0; i
< 6; i
++) Ofpack
[i
] = ' ';
478 (void) printf(gettext(
479 "\nvolcopy: IF REEL 1 HAS NOT BEEN RESTORED,"));
480 (void) printf(gettext(
481 " STOP NOW AND START OVER ***\07\n"));
482 if (!ask(" Continue? ")) {
486 strncpy(Ifname
, Fsys_p
, 6);
487 strncpy(Ifpack
, In
.f_vol_p
, 6);
489 if (V_labl
.v_reel
!= R_cur
|| V_labl
.v_reels
!= R_num
)
490 prompt(1, "Tape disagrees: Reel %d of %d : looking for %d of %d\n",
491 V_labl
.v_reel
, V_labl
.v_reels
, R_cur
, R_num
);
493 strncpy(V_labl
.v_volume
, Out
.f_vol_p
, 6);
494 strncpy(Ofpack
, Out
.f_vol_p
, 6);
495 strncpy(Ofname
, Fsys_p
, 6);
497 R_num
= Fs
/ R_blks
+ ((Fs
% R_blks
) ? 1 : 0);
498 (void) printf(gettext(
499 "You will need %d reels.\n"), R_num
);
500 (void) printf(gettext(
501 "(\tThe same size and density is expected for all reels)\n"));
504 if (NOT_EQ(Fsys_p
, Ifname
, 6)) {
505 verify
= !Otape
|| (altflg
& MINUSS
);
507 "arg. (%.6s) doesn't agree with from fs. (%.6s)\n",
510 if (NOT_EQ(In
.f_vol_p
, "-", 6) && NOT_EQ(In
.f_vol_p
, Ifpack
, 6)) {
511 verify
= !Otape
|| (altflg
& MINUSS
);
512 prompt(verify
, "arg. (%.6s) doesn't agree with from vol.(%.6s)\n",
516 if (*In
.f_vol_p
== '-')
518 if (*Out
.f_vol_p
== '-')
519 Out
.f_vol_p
= Ofpack
;
521 if (R_cur
== 1 && (Osup
.fs_time
+ _2_DAYS
) > Isup
.fs_time
) {
524 verify
= altflg
& MINUSS
;
525 t
= (time_t)Osup
.fs_time
;
526 prompt(verify
, "%s less than 48 hours older than %s\n"
527 "To filesystem dated: %s",
528 Out
.f_dev_p
, In
.f_dev_p
, ctime(&t
));
530 if (NOT_EQ(Out
.f_vol_p
, Ofpack
, 6)) {
531 prompt(1, "arg.(%.6s) doesn't agree with to vol.(%.6s)\n",
532 Out
.f_vol_p
, Ofpack
);
533 strncpy(Ofpack
, Out
.f_vol_p
, 6);
535 if (Isup
.fs_size
> Osup
.fs_size
&& !Otape
)
536 prompt(1, "from fs larger than to fs\n");
537 if (!Otape
&& NOT_EQ(Ifname
, Ofname
, 6)) {
538 verify
= altflg
& MINUSS
;
539 prompt(verify
, "warning! from fs(%.6s) differs from to fs(%.6s)\n",
543 (void) printf(gettext("From: %s, to: %s? "), In
.f_dev_p
, Out
.f_dev_p
);
544 if (!(altflg
& MINUSA
)) {
545 (void) printf(gettext("(DEL if wrong)\n"));
547 } else if (!ask("(y or n) "))
548 perr(10, "\nvolcopy: STOP\n");
552 In
.f_des
= open(In
.f_dev_p
, O_RDONLY
);
553 Out
.f_des
= open(Out
.f_dev_p
, O_WRONLY
);
555 if (g_init(&In
.f_dev
, &In
.f_des
) < 0 ||
556 g_init(&Out
.f_dev
, &Out
.f_des
) < 0)
557 perr(1, "volcopy: Error %d during initialization\n", errno
);
560 if (g_read(In
.f_dev
, In
.f_des
, &V_labl
, sizeof (V_labl
)) <
562 perr(10, "Error while reading label\n");
564 V_labl
.v_reels
= R_num
;
565 V_labl
.v_reel
= R_cur
;
566 V_labl
.v_time
= Tvec
;
567 V_labl
.v_reelblks
= R_blks
;
568 V_labl
.v_blksize
= BLKSIZ
* Blk_cnt
;
569 V_labl
.v_nblocks
= Blk_cnt
;
570 V_labl
.v_offset
= 0L;
571 V_labl
.v_type
= T_TYPE
;
573 if (g_write(Out
.f_dev
, Out
.f_des
, &V_labl
, sizeof (V_labl
)) <
575 perr(10, "Error while writing label\n");
579 Fs
= (R_cur
- 1) * actual_blocks();
580 lfdes
= Otape
? In
.f_des
: Out
.f_des
;
581 dist
= (long)(Fs
* BLKSIZ
);
582 } else { /* Eomflg */
584 perr(1, "Cannot use -reel with -e when copying to tape\n");
586 dist
= (long)(V_labl
.v_offset
* BLKSIZ
);
587 Fs
= V_labl
.v_offset
;
589 if (lseek(lfdes
, dist
, 0) < 0)
590 perr(1, "Cannot lseek()\n");
591 Sptr
= Otape
? &Isup
: &Osup
;
592 if ((Sptr
-> fs_magic
!= FS_MAGIC
) &&
593 (Sptr
-> fs_magic
!= MTB_UFS_MAGIC
))
594 perr(10, "File System type unknown--get help!\n");
596 if (Sptr
->fs_magic
== FS_MAGIC
&&
597 (Sptr
->fs_version
!= UFS_EFISTYLE4NONEFI_VERSION_2
&&
598 Sptr
->fs_version
!= UFS_VERSION_MIN
))
599 perr(10, "Unrecognized version of UFS--get help\n");
601 if (Sptr
->fs_magic
== MTB_UFS_MAGIC
&&
602 (Sptr
->fs_version
> MTB_UFS_VERSION_1
||
603 Sptr
->fs_version
< MTB_UFS_VERSION_MIN
))
604 perr(10, "Unrecognized version of UFS--get help\n");
606 Fs
= (Sptr
->fs_size
* Sptr
->fs_nspf
) - Fs
;
616 (void) printf(gettext(" END: %ld blocks.\n"), Blocks
);
623 return (31+1); /* failed.. 0 blocks */
627 * sigalrm: catch alarm signals.
635 (void) signal(SIGALRM
, sigalrm
);
639 * sigsys: catch illegal system calls to determine if IPC is available.
650 * sigint: catch interrupts and prompt user for shell or to quit.
657 extern char **environ
;
658 int tmpflg
, i
= 0, ps1
= -1, ps2
= -1;
660 tmpflg
= Yesflg
; /* override yesflag for duration of interrupt */
662 if (Shell_esc
&& ask("Want Shell? ")) {
664 /* both PS1 and PS2 must be exported */
666 if (EQ(environ
[i
], "PS1", 3))
668 if (EQ(environ
[i
], "PS2", 3))
672 if (ps1
>= 0 && ps2
>= 0)
673 environ
[ps1
] = environ
[ps2
];
674 (void) signal(SIGINT
, SIG_DFL
);
675 execl("/usr/bin/sh", "/usr/bin/sh", 0);
676 } else { /* parent */
677 (void) signal(SIGINT
, SIG_IGN
);
680 } else if (ask("Want to quit? ")) {
683 (void) cleanup(); /* ipc */
686 (void) signal(SIGINT
, sigint
);
687 Yesflg
= tmpflg
; /* reset Yesflg */
691 * actual_blocks: Calculate the actual number of blocks written to
692 * the tape (will differ from V_labl.v_reelblks if v_reelblks is not
693 * an even multiple of the blocking factor Blk_cnt).
700 if (R_blks
% Blk_cnt
)
701 return (((R_blks
/ Blk_cnt
) + 1) * Blk_cnt
);
707 * get_mach_type: Determine what machine this is executing on.
713 struct utsname utsinfo
;
716 if (uname(&utsinfo
) < 0)
717 perr(1, "Unable to determine machine type\n");
718 if (strcmp(utsinfo
.machine
, "3B2") == 0)
720 else if (strcmp(utsinfo
.machine
, "3B15") == 0)
725 * mem_setup: Determine memory needs and check for IPC. If IPC is available,
726 * used shared memory and semaphores to increase performance. If no IPC,
727 * get normal memory and only use one process.
739 struct semid_ds
*buf
;
765 if (Otape
|| Itape
) {
775 if (Blk_cnt
> 1) /* user overrode g_init */
776 In
.f_bsize
= Out
.f_bsize
= Blk_cnt
* BLKSIZ
;
777 In
.f_bsize
= (!Itape
) ? Disk_cnt
* In
.f_bsize
: In
.f_bsize
;
778 Out
.f_bsize
= (!Otape
) ? Disk_cnt
* Out
.f_bsize
: Out
.f_bsize
;
779 Bufsz
= find_lcm(In
.f_bsize
, Out
.f_bsize
);
780 num
= _128K
/ (Bufsz
+ sizeof (int));
782 size
= Bufsz
+ sizeof (int);
783 /* test to see if ipc is available, the shmat should fail with EINVAL */
784 (void) signal(SIGSYS
, sigsys
);
787 if ((int)shmat(0, NULL
, 0) < 0 && errno
!= EINVAL
)
788 Ipc
= 0; /* something went wrong */
790 if (Ipc
) { /* ipc is available */
793 for (cnt
= 0; cnt
< BUFCNT
; cnt
++) {
795 if ((Sem_id
[cnt
] = semget(IPC_PRIVATE
, 1, 0)) < 0)
796 perr(1, "Error allocating semaphores: %d",
798 if (semctl(Sem_id
[cnt
], 0, SETVAL
, sem_arg
) < 0)
799 perr(1, "Error setting semaphores: %d", errno
);
800 if ((Shm_id
[cnt
] = shmget(IPC_PRIVATE
, size
, 0)) < 0)
801 perr(1, "Error allocating shared memory: %d",
803 if ((Buf
[cnt
] = shmat(Shm_id
[cnt
], 0, 0)) == (void *)-1)
804 perr(1, "Error attaching shared memory: %d",
806 if (shmctl(Shm_id
[cnt
], SHM_LOCK
, 0) < 0)
807 perr(0, "Error locking in shared memory: %d",
809 Cnts
[cnt
] = (int *)(Buf
[cnt
] + Bufsz
);
811 } else { /* ipc is not available */
813 if ((Buf
[0] = align(size
)) == NULL
)
814 perr(1, "Out of memory\n");
815 Cnts
[0] = (int *)(Buf
[0] + Bufsz
);
821 * prompt: Prompt the user for verification.
825 prompt(int verify
, const char *fmt
, ...)
831 (void) vfprintf(stdout
, gettext(fmt
), ap
);
834 (void) fprintf(stdout
, gettext("Type 'y' to override: "));
843 * ask: Ask the user a question and get the answer.
851 (void) printf(gettext(s
));
853 (void) printf(gettext("YES\n"));
857 fgets(ans
, 10, Devtty
);
862 if (Pid
> 0) /* parent with a child */
873 (void) printf(gettext("\n(y or n)?"));
874 fgets(ans
, 10, Devtty
);
880 * align: Align a malloc'd memory section on a page boundry.
888 if ((pad
= ((int)malloc(0) & (PAGESIZE
-1))) > 0) {
889 pad
= PAGESIZE
- pad
;
890 if (malloc(pad
) == NULL
)
893 return (malloc((unsigned)size
));
897 * child_copy: Using IPC, this child process reads from shared memory
898 * and writes to the destination file system.
904 int rv
, cur_buf
, left
, have
, tpcnt
;
907 (void) signal(SIGINT
, SIG_IGN
);
909 (void) close(In
.f_des
);
910 if (Otape
&& !Eomflg
)
911 tpcnt
= actual_blocks() * BLKSIZ
;
914 if (semop(Sem_id
[cur_buf
], &Sem_buf
, 1) < 0)
915 perr(1, "semaphore operation error %d\n", errno
);
916 left
= *Cnts
[cur_buf
];
922 have
= (left
< Out
.f_bsize
) ? left
: Out
.f_bsize
;
923 if (!Eomflg
&& Otape
) {
925 (void) chgreel(&Out
, OUTPUT
);
926 tpcnt
= actual_blocks() * BLKSIZ
;
928 have
= (tpcnt
< have
) ? tpcnt
: have
;
931 if ((rv
= g_write(Out
.f_dev
, Out
.f_des
, c_p
, have
)) <
933 if (Eomflg
&& errno
== ENOSPC
) {
934 (void) chgreel(&Out
, OUTPUT
);
937 perr(1, "I/O error %d on write\n",
942 V_labl
.v_offset
+= rv
;
943 if (!Eomflg
&& Otape
)
946 if (semop(Sem_id
[cur_buf
], &Sem_buf
, 1) < 0)
947 perr(2, "semaphore operation error %d\n", errno
);
948 cur_buf
= (cur_buf
+ 1) % BUFCNT
;
954 * parent_copy: Using shared memory, the parent process reads fromt the
955 * source file system and writes to shared memory.
961 int rv
, left
, have
, tpcnt
, cur_buf
;
963 int eom
= 0, xfer_cnt
= Fs
* BLKSIZ
;
967 if ((Pid
= fork()) == 0)
968 child_copy(); /* child does not return */
969 (void) close(Out
.f_des
);
970 Rstsem_buf
.sem_num
= 0;
971 Rstsem_buf
.sem_flg
= 0;
972 Rstsem_buf
.sem_op
= 2;
975 if (Itape
&& !Eomflg
)
976 tpcnt
= actual_blocks() * BLKSIZ
;
978 if (semop(Sem_id
[cur_buf
], &Sem_buf
, 1) < 0)
979 perr(1, "Semaphore operation error %d\n", errno
);
983 while (left
>= In
.f_bsize
&& xfer_cnt
) {
984 have
= (xfer_cnt
< In
.f_bsize
) ? xfer_cnt
: In
.f_bsize
;
985 if (!Eomflg
&& Itape
) {
987 *Cnts
[cur_buf
] = Bufsz
- left
;
988 (void) flush_bufs(cur_buf
);
989 (void) chgreel(&In
, INPUT
);
990 tpcnt
= actual_blocks() * BLKSIZ
;
991 cur_buf
= (cur_buf
== 0) ? 1 : 0;
995 have
= (tpcnt
< have
) ? tpcnt
: have
;
998 if ((rv
= g_read(In
.f_dev
, In
.f_des
, c_p
, have
)) < 0) {
999 if (Eomflg
&& errno
== ENOSPC
) {
1000 *Cnts
[cur_buf
] = Bufsz
- left
;
1001 (void) flush_bufs(cur_buf
);
1002 (void) chgreel(&In
, INPUT
);
1003 cur_buf
= (cur_buf
== 0) ? 1 : 0;
1007 perr(1, "I/O error %d on read\n",
1013 if (!Eomflg
&& Itape
)
1024 *Cnts
[cur_buf
] = Bufsz
- left
;
1025 Blocks
+= *Cnts
[cur_buf
];
1026 if (semop(Sem_id
[cur_buf
], &Rstsem_buf
, 1) < 0)
1027 perr(2, "Semaphore operation error %d\n", errno
);
1028 cur_buf
= (cur_buf
== 0) ? 1 : 0;
1030 if (semop(Sem_id
[cur_buf
], &Sem_buf
, 1) < 0)
1031 perr(3, "Semaphore operation error %d\n", errno
);
1033 if (semop(Sem_id
[cur_buf
], &Rstsem_buf
, 1) < 0)
1034 perr(4, "Semaphore operation error %d\n", errno
);
1040 * copy: Copy without shared memory. The process reads from the source
1041 * filesystem and writes to the destination filesystem.
1047 int rv
, left
, have
, tpcnt
= 1, xfer_cnt
= Fs
* BLKSIZ
;
1050 if ((Itape
|| Otape
) && !Eomflg
)
1051 tpcnt
= actual_blocks() * BLKSIZ
;
1053 c_p
= (char *)(Buf
[0] + *Cnts
[0]);
1054 left
= Bufsz
- *Cnts
[0];
1056 while (left
>= In
.f_bsize
&& xfer_cnt
) {
1057 have
= (xfer_cnt
< In
.f_bsize
) ? xfer_cnt
: In
.f_bsize
;
1058 if (!Eomflg
&& Itape
) {
1060 *Cnts
[0] = Bufsz
- left
;
1061 (void) chgreel(&In
, INPUT
);
1062 tpcnt
= actual_blocks() * BLKSIZ
;
1065 have
= (tpcnt
< have
) ? tpcnt
: have
;
1068 if ((rv
= g_read(In
.f_dev
, In
.f_des
, c_p
, have
)) < 0) {
1069 if (Eomflg
&& errno
== ENOSPC
) {
1070 (void) chgreel(&In
, INPUT
);
1073 perr(1, "I/O error %d on read\n",
1079 if (!Eomflg
&& Itape
)
1081 } /* left >= In.f_bsize && xfer_cnt */
1082 *Cnts
[0] = Bufsz
- left
;
1087 while (left
>= Out
.f_bsize
|| (left
> 0 && !xfer_cnt
)) {
1088 have
= (left
< Out
.f_bsize
) ? left
: Out
.f_bsize
;
1089 if (!Eomflg
&& Otape
) {
1091 (void) chgreel(&Out
, OUTPUT
);
1092 tpcnt
= actual_blocks() * BLKSIZ
;
1094 have
= (tpcnt
< have
) ? tpcnt
: have
;
1097 if ((rv
= g_write(Out
.f_dev
, Out
.f_des
, c_p
, have
)) <
1099 if (Eomflg
&& errno
== ENOSPC
) {
1100 (void) chgreel(&Out
, OUTPUT
);
1103 perr(1, "I/O error %d on write\n",
1108 V_labl
.v_offset
+= rv
;
1109 if (!Eomflg
&& Otape
)
1111 } /* left >= Out.f_bsize */
1113 (void) memcpy(Buf
[0], c_p
, left
);
1122 * flush_bufs: Permit child to read the remaining data from the
1123 * buffer before prompting user for end-of-media.
1127 flush_bufs(int buffer
)
1130 Blocks
+= *Cnts
[buffer
];
1131 if (semop(Sem_id
[buffer
], &Rstsem_buf
, 1) < 0)
1132 perr(5, "Semaphore operation error %d\n", errno
);
1133 if (semop(Sem_id
[buffer
], &Sem_buf
, 1) < 0)
1134 perr(6, "Semaphore operation error %d\n", errno
);
1138 * cleanup: Clean up shared memory and semaphore resources.
1147 for (cnt
= 0; cnt
< BUFCNT
; cnt
++) {
1148 (void) semctl(Sem_id
[cnt
], IPC_RMID
, 0);
1149 (void) shmctl(Shm_id
[cnt
], IPC_RMID
, 0);
1155 * find_lcm: Find the lowest common multiple of two numbers. This is used
1156 * to determine the buffer size that should be malloc(3)'d such that the
1157 * input and output data blocks can both fit evenly into the buffer.
1161 find_lcm(int sz1
, int sz2
)
1163 int inc
, lcm
, small
;
1168 } else { /* sz1 >= sz2 */
1172 while (lcm
% small
!= 0)
1178 * Determine bpi information from drive names.
1186 * Kludge to recognize Accellerated Tape Controller usage from
1187 * letter 'a' or 'A' following density given by user.
1189 * Kludge to recognize 3B15 Compatibility Mode from
1190 * letter 'c' or 'C' following density given by user.
1193 if (inp
[4] == 'a' || inp
[4] == 'A') {
1194 Drive_typ
= A_DRIVE
;
1197 if (inp
[4] == 'c' || inp
[4] == 'C') {
1198 Drive_typ
= C_DRIVE
;
1206 * blks_per_ft: Determine the number of blocks per foot of tape.
1207 * Inter-block gap (dgap) is 0.3 in.
1211 blks_per_ft(double disc
)
1213 double dcnt
= Blk_cnt
, dBpi
= Bpi
, dsiz
= BLKSIZ
, dgap
= 0.3;
1215 return ((int)(dcnt
/ (((dcnt
* dsiz
/ dBpi
) + dgap
) / 12.0) * disc
));
1219 * tapeck: Arbitrary block size. Determine the number of physical blocks per
1220 * foot of tape, including the inter-block gap, and the possibility of a short
1221 * tape. Assume the usable portion of a tape is 85% of its length for small
1222 * block sizes and 88% for large block sizes.
1226 tapeck(struct file_info
*f_p
, int dir
)
1228 int again
= 1, verify
, old_style
, new_style
;
1232 if ((f_p
->f_bsize
= g_init(&f_p
->f_dev
, &f_p
->f_des
)) < 0)
1233 perr(1, "volcopy: Error %d during initialization\n", errno
);
1234 if ((f_p
->f_dev
!= G_TM_TAPE
) && (f_p
->f_dev
!= G_XT_TAPE
) &&
1235 (f_p
->f_dev
!= G_ST_TAPE
))
1237 V_labl
.v_magic
[0] = '\0'; /* scribble on old data */
1239 if (g_read(f_p
->f_dev
, f_p
->f_des
, &V_labl
, sizeof (V_labl
)) <= 0) {
1241 perror("input tape");
1243 perror("output tape");
1246 if (V_labl
.v_reel
== '\0' && dir
== INPUT
)
1247 perr(9, "Input tape is empty\n");
1249 old_style
= strncmp(V_labl
.v_magic
, "Volcopy", 7) == 0;
1250 new_style
= strncmp(V_labl
.v_magic
, "VOLCOPY", 7) == 0;
1251 if (!old_style
&& !new_style
) {
1252 verify
= (dir
== INPUT
) ? 0 : 1;
1253 prompt(verify
, "Not a labeled tape\n");
1255 perr(10, "Input tape not made by volcopy\n");
1257 strncpy(V_labl
.v_volume
, f_p
->f_vol_p
, 6);
1259 } else if (new_style
) {
1260 Eomflg
= (dir
== INPUT
) ? 1 : Eomflg
;
1262 strncpy(V_labl
.v_magic
, "Volcopy", 7);
1265 if (*f_p
->f_vol_p
== '-')
1266 strncpy(f_p
->f_vol_p
, V_labl
.v_volume
, 6);
1267 else if (NOT_EQ(V_labl
.v_volume
, f_p
->f_vol_p
, 6)) {
1268 prompt(1, "Header volume(%.6s) does not match (%s)\n",
1269 V_labl
.v_volume
, f_p
->f_vol_p
);
1270 strncpy(V_labl
.v_volume
, f_p
->f_vol_p
, 6);
1273 Bpi
= V_labl
.v_dens
;
1275 R_len
= V_labl
.v_length
;
1276 R_num
= V_labl
.v_reels
;
1279 if (V_labl
.v_type
== T_TYPE
) {
1280 if (V_labl
.v_nblocks
== 0) {
1282 Drive_typ
= C_DRIVE
;
1284 Blk_cnt
= V_labl
.v_nblocks
;
1285 if (V_labl
.v_nblocks
== 32)
1286 Drive_typ
= A_DRIVE
;
1292 Drive_typ
= C_DRIVE
;
1296 while (!Eomflg
&& (R_len
<= 0 || R_len
> 3600)) {
1297 (void) printf(gettext(
1298 "Enter size of reel in feet for <%s>: "),
1300 fgets(resp
, 10, Devtty
);
1302 if (R_len
> 0 && R_len
<= 3600)
1304 perr(0, "Size of reel must be > 0, <= 3600\n");
1306 while (!Eomflg
&& again
) {
1309 (void) printf(gettext(
1310 "Tape density? (i.e., 800 | 1600 | 6250)? "));
1311 fgets(resp
, 10, Devtty
);
1316 R_blks
= Ft800x10
* R_len
;
1321 case 1: /* Writing a new tape */
1322 if (Drive_typ
== A_DRIVE
)
1323 R_blks
= Ft1600x32
* R_len
;
1324 else if (Drive_typ
== C_DRIVE
)
1325 R_blks
= Ft1600x10
* R_len
;
1327 R_blks
= Ft1600x16
* R_len
;
1330 R_blks
= Ft1600x10
* R_len
;
1333 R_blks
= Ft1600x16
* R_len
;
1336 R_blks
= Ft1600x32
* R_len
;
1340 R_blks
= blks_per_ft(0.85);
1342 R_blks
= blks_per_ft(0.88);
1346 R_blks
= Ft1600x10
* R_len
;
1351 case 1: /* Writing a new tape */
1352 if (Drive_typ
== A_DRIVE
)
1353 R_blks
= Ft6250x32
* R_len
;
1354 else if (Drive_typ
== C_DRIVE
)
1355 R_blks
= Ft6250x10
* R_len
;
1357 R_blks
= Ft6250x16
* R_len
;
1360 R_blks
= Ft6250x10
* R_len
;
1363 R_blks
= Ft6250x16
* R_len
;
1366 R_blks
= Ft6250x32
* R_len
;
1370 R_blks
= blks_per_ft(0.85);
1372 R_blks
= blks_per_ft(0.88);
1376 R_blks
= Ft6250x50
* R_len
;
1379 perr(0, "Bpi must be 800, 1600, or 6250\n");
1384 (void) printf(gettext("\nReel %.6s"), V_labl
.v_volume
);
1386 V_labl
.v_length
= R_len
;
1387 V_labl
.v_dens
= Bpi
;
1388 (void) printf(gettext(", %d feet, %d BPI\n"), R_len
, Bpi
);
1390 (void) printf(gettext(", ? feet\n"));
1395 * hdrck: Look for and validate a volcopy style tape label.
1399 hdrck(int dev
, int fd
, char *tvol
)
1402 struct volcopy_label tlabl
;
1404 alarm(15); /* don't scan whole tape for label */
1406 if (g_read(dev
, fd
, &tlabl
, sizeof (tlabl
)) != sizeof (tlabl
)) {
1409 prompt(verify
, "Cannot read header\n");
1413 strncpy(V_labl
.v_volume
, tvol
, 6);
1417 V_labl
.v_reel
= tlabl
.v_reel
;
1418 if (NOT_EQ(tlabl
.v_volume
, tvol
, 6)) {
1419 perr(0, "Volume is <%.6s>, not <%s>.\n", tlabl
.v_volume
, tvol
);
1420 if (ask("Want to override? ")) {
1422 strncpy(V_labl
.v_volume
, tvol
, 6);
1424 strncpy(tvol
, tlabl
.v_volume
, 6);
1433 * mklabel: Zero out and initialize a volcopy label.
1440 (void) memcpy(&V_labl
, Empty
, sizeof (V_labl
));
1442 (void) strcpy(V_labl
.v_magic
, "Volcopy");
1444 (void) strcpy(V_labl
.v_magic
, "VOLCOPY");
1448 * rprt: Report activity to user.
1456 (void) printf(gettext("\nReading "));
1458 (void) printf(gettext("\nWriting "));
1460 (void) printf(gettext(
1461 "REEL %d of %d VOL = %.6s\n"),
1462 R_cur
, R_num
, In
.f_vol_p
);
1464 (void) printf(gettext(
1465 "REEL %d of ? VOL = %.6s\n"), R_cur
, In
.f_vol_p
);
1470 * fslog: Log current activity.
1478 fp
= fopen("/var/log/filesave.log", "a");
1480 perr(1, "volcopy: cannot open /var/log/filesave.log\n");
1483 fprintf(fp
, "%s%c%.6s%c%.6s -> %s%c%.6s%c%.6s on %.24s\n",
1484 In
.f_dev_p
, ';', Ifname
, ';', Ifpack
, Out
.f_dev_p
,
1485 ';', Ofname
, ';', Ofpack
, ctime(&Tvec
));
1492 * getname: Get device name.
1496 getname(char *nam_p
)
1502 (void) printf(gettext("Changing drives? (type RETURN for no,\n"));
1503 (void) printf(gettext("\t`/dev/rmt/??\' or `/dev/rtp/??\' for yes: "));
1504 fgets(nam_buf
, 20, Devtty
);
1506 lastchar
= strlen(nam_buf
) - 1;
1507 if (nam_buf
[lastchar
] == '\n')
1508 nam_buf
[lastchar
] = '\0'; /* remove it */
1509 if (nam_buf
[0] != '\0')
1510 (void) strcpy(nam_p
, nam_buf
);
1514 * chgreel: Change reel on end-of-media.
1518 chgreel(struct file_info
*f_p
, int dir
)
1520 int again
= 1, lastchar
, temp
;
1527 (void) close(f_p
->f_des
);
1528 (void) getname(f_p
->f_dev_p
);
1529 (void) printf(gettext(
1530 "Mount tape %d\nType volume-ID when ready: "), R_cur
);
1532 fgets(vol_tmp
, 10, Devtty
);
1534 lastchar
= strlen(vol_tmp
) - 1;
1535 if (vol_tmp
[lastchar
] == '\n')
1536 vol_tmp
[lastchar
] = '\0'; /* remove it */
1537 if (vol_tmp
[0] != '\0') { /* if null string, use old vol-id */
1538 strncpy(f_p
->f_vol_p
, vol_tmp
, 6);
1539 strncpy(V_labl
.v_volume
, vol_tmp
, 6);
1542 f_p
->f_des
= open(f_p
->f_dev_p
, O_RDONLY
);
1543 if (f_p
->f_des
<= 0 || f_p
->f_des
> 10) {
1545 perror("input ERR");
1547 perror("output ERR");
1550 if (g_init(&(f_p
->f_dev
), &(f_p
->f_des
)) < 0)
1551 perr(0, "Initialization error %d\n", errno
);
1552 if ((f_p
->f_dev
!= G_TM_TAPE
) && (f_p
->f_dev
!= G_XT_TAPE
) &&
1553 (f_p
->f_dev
!= G_ST_TAPE
)) {
1554 (void) printf(gettext(
1555 "\n'%s' is not a valid device"), f_p
->f_dev_p
);
1556 (void) printf(gettext(
1557 "\n\tenter device name `/dev/rmt/??\' or `/dev/rtp/??\' :"));
1561 if (!hdrck(f_p
->f_dev
, f_p
->f_des
, f_p
->f_vol_p
)) {
1567 if (V_labl
.v_reel
!= R_cur
) {
1568 perr(0, "Need reel %d, label says reel %d\n",
1569 R_cur
, V_labl
.v_reel
);
1575 V_labl
.v_reel
= R_cur
;
1576 temp
= V_labl
.v_offset
;
1577 V_labl
.v_offset
/= BUFSIZ
;
1581 f_p
->f_des
= open(f_p
->f_dev_p
, O_WRONLY
);
1582 if (f_p
->f_des
<= 0 || f_p
->f_des
> 10)
1583 perror("output ERR");
1585 if (g_init(&(f_p
->f_dev
), &(f_p
->f_des
)) < 0)
1586 perr(1, "Initialization error %d\n", errno
);
1588 if (g_write(f_p
->f_dev
, f_p
->f_des
, &V_labl
,
1589 sizeof (V_labl
)) < 0) {
1590 perr(0, "Cannot re-write header -Try again!\n");
1592 V_labl
.v_offset
= temp
;
1595 V_labl
.v_offset
= temp
;
1598 perr(1, "Impossible case\n");
1605 * perr: Print error messages.
1609 perr(int severity
, const char *fmt
, ...)
1614 (void) fflush(stdout
);
1615 (void) fflush(stderr
);
1616 if (severity
== 10) {
1617 (void) vfprintf(stdout
, gettext(fmt
), ap
);
1618 (void) fprintf(stdout
, gettext(
1619 "\t%d reel(s) completed\n"), --R_cur
);
1620 (void) fflush(stdout
);
1621 (void) fflush(stderr
);
1625 (void) vfprintf(stderr
, gettext(fmt
), ap
);
1626 (void) fflush(stderr
);
1636 getinfs(int dev
, int fd
, char *buf
)
1641 if (lseek(fd
, SBLOCK
* DEV_BSIZE
, 0) != SBLOCK
* DEV_BSIZE
) {
1642 perr(10, "Unable to lseek on input\n");
1644 cnt
= SBSIZE
/DEV_BSIZE
;
1645 for (i
= 0; i
< cnt
; i
++) {
1646 if (g_read(dev
, fd
, (char *)buf
+ i
*DEV_BSIZE
, DEV_BSIZE
)
1648 perr(10, "Unable to read on input\n");
1654 getoutfs(int dev
, int fd
, char *buf
, int verify
)
1660 if (lseek(fd
, SBLOCK
* DEV_BSIZE
, 0) != SBLOCK
* DEV_BSIZE
) {
1661 prompt(verify
, "Unable to lseek on output\n", errno
);
1663 cnt
= SBSIZE
/DEV_BSIZE
;
1664 for (i
= 0; i
< cnt
; i
++) {
1665 if (g_read(dev
, fd
, (char *)buf
+ i
*DEV_BSIZE
, DEV_BSIZE
)
1667 prompt(verify
, "Unable to read on output\n", errno
);
1673 getfslabel(struct fs
*sb
)
1679 * is there room for label?
1682 if (sb
->fs_cpc
<= 0)
1686 * calculate the available blocks for each rotational position
1688 blk
= sb
->fs_spc
* sb
->fs_cpc
/ sb
->fs_nspf
;
1689 for (i
= 0; i
< blk
; i
+= sb
->fs_frag
)
1692 blk
= i
/ sb
->fs_frag
;
1694 return ((char *)&(fs_rotbl(sb
)[blk
]));
1698 getvolabel(struct fs
*sb
)
1705 if (p
== nolabel
|| p
== NULL
)
1708 for (i
= 0; *p
&& i
< 6; p
++, i
++)