volcopy.c revision d1a180b0452ce86577a43be3245d2eacdeec1a34
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <signal.h>
#include <sys/sysmacros.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include <archives.h>
#include "volcopy.h"
#include <locale.h>
/*
* main I/O information structure, contains information for the
* source and destination files.
*/
struct file_info {
char *f_dev_p, /* name of device */
*f_vol_p; /* volume name */
int f_bsize, /* size to buffer I/O to */
f_des, /* file descriptor */
f_dev; /* device type (generic I/O library) */
Rstsem_buf; /* semaphore reset operation buffer */
typedef union {
} sb_un;
struct volcopy_label V_labl;
*Fsys_p;
Blocks = 0, /* Number of blocks transferred */
Bpi = 0,
Bufflg = 0,
Drive_typ = 0, /* Flag for special tape drive types */
Eomflg = 0,
Ipc = 0,
M3b15 = 0, /* Machine types, set to 1 for the machine */
M3b2 = 0, /* the command is executing on */
Pid = -1,
R_blks = 0, /* Number of blocks per tape reel */
R_len = 0, /* Length in feet of tape reels */
R_num = 0, /* Number of tape reels to be processed */
Yesflg = 0;
void (*singal())();
long Fs,
static void getinfs(),
getoutfs();
static char *getfslabel(struct fs *);
static char *getvolabel(struct fs *);
static void prompt(int, const char *, ...);
static void perr(int, const char *, ...);
static void mklabel(void);
static void get_mach_type(void);
static void mem_setup(void);
static void rprt(void);
static void parent_copy(void);
static void copy(void);
static void flush_bufs(int);
static void cleanup(void);
#ifdef LOG
static int fslog(void);
#endif /* LOG */
/*
* g_init(), g_read(), g_write() originally came from libgenIO,
* a totally obsolete device interface library, now deleted.
* volcopy should be deleted too, since it doesn't work.
*/
/*
* g_init: Determine the device being accessed, set the buffer size,
* and perform any device specific initialization. Since at this point
* Sun has no system call to read the configuration, the major numbers
* are assumed to be static and types are figured out as such. However,
* as a rough estimate, the buffer size for all types is set to 512
* as a default.
*/
static int
{
int bufsize;
return (-1);
bufsize = 512;
else {
/* find block size for this file system */
bufsize = -1;
} else {
}
}
return (bufsize);
}
return (512);
}
/*
* g_read: Read nbytes of data from fdes (of type devtype) and place
* data in location pointed to by buf. In case of end of medium,
* translate (where necessary) device specific EOM indications into
* the generic EOM indication of rv = -1, errno = ENOSPC.
*/
/* ARGSUSED */
static ssize_t
{
/* st devices return 0 when no space left */
rv = -1;
}
return (rv);
}
/*
* g_write: Write nbytes of data to fdes (of type devtype) from
* the location pointed to by buf. In case of end of medium,
* translate (where necessary) device specific EOM indications into
* the generic EOM indication of rv = -1, errno = ENOSPC.
*/
/* ARGSUSED */
static ssize_t
{
/* st devices return 0 when no more space left */
rv = -1;
}
return (rv);
}
/*
* filesystem copy with propagation of volume ID and filesystem name:
*
*
* options are:
* -feet - length of tape
* -bpi - recording density
* -reel - reel number (if not starting from beginning)
* -buf - use double buffered i/o (if dens >= 1600 bpi)
* -block - Set the transfer block size to NUM physical blocks (512
* bytes on 3B2 and 3B15). Note that an arbitrary block size might
* or might not work on a given system. Also, the block size
* read from the header of an input tape silently overrides this.
* -nosh - Don't offer the user a shell after hitting break or delete.
* -r - Read NUM transfer blocks from the disk at once and write it
* to the output device one block at a time. Intended only to
* boost the 3B15 EDFC disk to tape performance. Disabled on 3B2.
* -a - ask "y or n" instead of "DEL if wrong"
* User has 10 seconds to DEL if mistaken!
* -y - assume "yes" response to all questions
*
* Examples:
*
*
*
*/
int
{
char c;
long dist;
char *align();
int cnt;
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
(void) get_mach_type();
Eomflg = 1;
Yesflg++;
Bufflg++;
else {
++argv;
--argc;
}
else {
++argv;
--argc;
}
else {
++argv;
--argc;
}
else {
++argv;
--argc;
}
if (Disk_cnt == 0)
else {
++argv;
--argc;
}
if (Blk_cnt == 0)
Shell_esc = 0;
} else
++argv;
--argc;
} /* argv[1][0] == '-' */
fsname /devfrom volfrom /devto volto\n");
(void) mem_setup();
R_cur = 1;
/* read in superblock */
verify = 0;
} /* R_cur == 1 || !Itape */
/* read in superblock */
} else {
int i;
/* out vol does not contain a ufs file system */
/* stuff let over from Isup */
/* wipe out the fs name and pack name for warning purposes */
}
if (Itape) {
if (R_cur != 1) {
"\nvolcopy: IF REEL 1 HAS NOT BEEN RESTORED,"));
" STOP NOW AND START OVER ***\07\n"));
if (!ask(" Continue? ")) {
cleanup();
}
}
} else if (Otape) {
if (!Eomflg) {
"You will need %d reels.\n"), R_num);
"(\tThe same size and density is expected for all reels)\n"));
}
}
"arg. (%.6s) doesn't agree with from fs. (%.6s)\n",
}
}
time_t t;
"To filesystem dated: %s",
}
}
}
sleep(10);
} else if (!ask("(y or n) "))
sync();
errno = 0;
if (Itape) {
errno = 0;
sizeof (V_labl))
} else if (Otape) {
errno = 0;
sizeof (V_labl))
}
if (R_cur > 1) {
if (!Eomflg) {
} else { /* Eomflg */
if (Otape)
}
}
rprt();
if (Ipc) {
parent_copy();
(void) cleanup();
} else
copy();
#ifdef LOG
fslog();
#endif
if (Blocks)
return (0);
return (31+1); /* failed.. 0 blocks */
}
/*
* sigalrm: catch alarm signals.
*/
void
sigalrm()
{
void (*signal())();
}
/*
* sigsys: catch illegal system calls to determine if IPC is available.
*/
void
sigsys()
{
Ipc = 0;
}
/*
* sigint: catch interrupts and prompt user for shell or to quit.
*/
void
sigint()
{
void (*signal())();
extern char **environ;
Yesflg = 0;
if (!fork()) {
/* both PS1 and PS2 must be exported */
while (environ[i]) {
ps1 = i;
ps2 = i;
i++;
}
} else { /* parent */
wait((int *)0);
}
} else if (ask("Want to quit? ")) {
if (Pid > 0)
(void) cleanup(); /* ipc */
}
}
/*
* actual_blocks: Calculate the actual number of blocks written to
* the tape (will differ from V_labl.v_reelblks if v_reelblks is not
* an even multiple of the blocking factor Blk_cnt).
*/
int
{
else
return (R_blks);
}
/*
* get_mach_type: Determine what machine this is executing on.
*/
static void
get_mach_type(void)
{
errno = 0;
M3b2 = 1;
M3b15 = 1;
}
/*
* mem_setup: Determine memory needs and check for IPC. If IPC is available,
* used shared memory and semaphores to increase performance. If no IPC,
* get normal memory and only use one process.
*/
static void
mem_setup(void)
{
void (*signal())();
char *align();
union semun {
int val;
} sem_arg;
if (Blk_cnt == 1) {
switch (Drive_typ) {
case A_DRIVE:
Blk_cnt = 32;
break;
case C_DRIVE:
Blk_cnt = 10;
break;
case K_DRIVE:
Blk_cnt = 4;
break;
case T_DRIVE:
if (Bpi == 6250)
Blk_cnt = 50;
else
Blk_cnt = 10;
break;
default:
if (M3b15) {
Blk_cnt = 16;
} else {
if (Bpi == 6250)
Blk_cnt = 50;
else
Blk_cnt = 10;
}
}
break;
} /* Drive_typ */
} /* Blk_cnt == 1 */
/* test to see if ipc is available, the shmat should fail with EINVAL */
errno = 0;
if (Ipc) {
Ipc = 0; /* something went wrong */
}
if (Ipc) { /* ipc is available */
Bufcnt = 2;
errno = 0;
errno);
errno);
errno);
perr(0, "Error locking in shared memory: %d",
errno);
}
} else { /* ipc is not available */
Bufcnt = 1;
*Cnts[0] = 0;
}
}
/*
* prompt: Prompt the user for verification.
*/
static void
{
if (verify) {
if (!ask("")) {
cleanup();
}
}
}
/*
* ask: Ask the user a question and get the answer.
*/
int
ask(char *s)
{
char ans[12];
if (Yesflg) {
return (1);
}
ans[0] = '\0';
for (;;) {
switch (ans[0]) {
case 'a':
case 'A':
if (Pid > 0) /* parent with a child */
cleanup();
case 'y':
case 'Y':
return (1);
case 'n':
case 'N':
return (0);
default:
}
}
}
/*
* align: Align a malloc'd memory section on a page boundry.
*/
char *
{
int pad;
return ((char *)NULL);
}
}
/*
* child_copy: Using IPC, this child process reads from shared memory
* and writes to the destination file system.
*/
int
{
char *c_p;
cur_buf = 0;
for (;;) {
if (!left)
break;
rv = 0;
while (left) {
if (!tpcnt) {
}
}
errno = 0;
0) {
continue;
} else
errno);
}
}
}
exit(0);
}
/*
* parent_copy: Using shared memory, the parent process reads fromt the
* source file system and writes to shared memory.
*/
static void
parent_copy(void)
{
char *c_p;
child_copy(); /* child does not return */
Rstsem_buf.sem_num = 0;
Rstsem_buf.sem_flg = 0;
cur_buf = 0;
while (xfer_cnt) {
rv = 0;
if (!tpcnt) {
(void) flush_bufs(cur_buf);
eom = 1;
break;
}
}
errno = 0;
(void) flush_bufs(cur_buf);
eom = 1;
break;
} else
errno);
}
}
if (eom > 0) {
eom = 0;
if (Eomflg)
else if (Itape)
continue;
}
}
}
/*
* copy: Copy without shared memory. The process reads from the source
* filesystem and writes to the destination filesystem.
*/
static void
copy(void)
{
char *c_p;
while (xfer_cnt) {
rv = 0;
if (!tpcnt) {
break;
}
}
errno = 0;
break;
} else
errno);
}
} /* left >= In.f_bsize && xfer_cnt */
rv = 0;
if (!tpcnt) {
}
}
errno = 0;
0) {
continue;
} else
errno);
}
} /* left >= Out.f_bsize */
if (left) {
}
} /* xfer_cnt */
}
/*
* flush_bufs: Permit child to read the remaining data from the
* buffer before prompting user for end-of-media.
*/
static void
flush_bufs(int buffer)
{
}
/*
* cleanup: Clean up shared memory and semaphore resources.
*/
static void
cleanup(void)
{
int cnt;
if (Ipc) {
}
}
}
/*
* find_lcm: Find the lowest common multiple of two numbers. This is used
* to determine the buffer size that should be malloc(3)'d such that the
* input and output data blocks can both fit evenly into the buffer.
*/
int
{
} else { /* sz1 >= sz2 */
}
return (lcm);
}
/*
* Determine bpi information from drive names.
*/
int
{
/*
* Kludge to recognize Accellerated Tape Controller usage from
* letter 'a' or 'A' following density given by user.
*
* Kludge to recognize 3B15 Compatibility Mode from
* letter 'c' or 'C' following density given by user.
*/
if (M3b15) {
}
}
}
}
/*
* blks_per_ft: Determine the number of blocks per foot of tape.
* Inter-block gap (dgap) is 0.3 in.
*/
int
blks_per_ft(double disc)
{
}
/*
* tapeck: Arbitrary block size. Determine the number of physical blocks per
* foot of tape, including the inter-block gap, and the possibility of a short
* tape. Assume the usable portion of a tape is 85% of its length for small
* block sizes and 88% for large block sizes.
*/
int
{
char resp[16];
errno = 0;
return (0);
alarm(5);
perror("input tape");
else
perror("output tape");
}
alarm(0);
else {
mklabel();
} else if (new_style) {
if (!Eomflg)
}
}
}
if (!Eomflg) {
}
if (M3b15) {
Blk_cnt = 10;
} else
else
Drive_typ = 0;
} else {
Drive_typ = 0;
Blk_cnt = 10;
}
}
}
"Enter size of reel in feet for <%s>: "),
break;
perr(0, "Size of reel must be > 0, <= 3600\n");
}
again = 0;
if (!Bpi) {
"Tape density? (i.e., 800 | 1600 | 6250)? "));
}
switch (Bpi) {
case 800:
break;
case 1600:
if (M3b15) {
switch (Blk_cnt) {
case 1: /* Writing a new tape */
else
break;
case 10:
break;
case 16:
break;
case 32:
break;
default:
if (Blk_cnt < 32)
else
} /* Blk_cnt */
} else
break;
case 6250:
if (M3b15) {
switch (Blk_cnt) {
case 1: /* Writing a new tape */
else
break;
case 10:
break;
case 16:
break;
case 32:
break;
default:
if (Blk_cnt < 32)
else
}
} else
break;
default:
perr(0, "Bpi must be 800, 1600, or 6250\n");
Bpi = 0;
again = 1;
} /* Bpi */
} /* again */
if (!Eomflg) {
} else
return (1);
}
/*
* hdrck: Look for and validate a volcopy style tape label.
*/
int
{
int verify;
struct volcopy_label tlabl;
errno = 0;
alarm(0);
if (Itape)
else
return (verify);
}
alarm(0);
if (ask("Want to override? ")) {
if (Otape)
else
return (1);
}
return (0);
}
return (1);
}
/*
* mklabel: Zero out and initialize a volcopy label.
*/
static void
mklabel(void)
{
if (!Eomflg)
else
}
/*
* rprt: Report activity to user.
*/
static void
rprt(void)
{
if (Itape)
else /* Otape */
if (!Eomflg)
"REEL %d of %d VOL = %.6s\n"),
else
}
#ifdef LOG
/*
* fslog: Log current activity.
*/
static int
fslog(void)
{
}
return (0);
}
#endif /* LOG */
/*
* getname: Get device name.
*/
void
{
int lastchar;
char nam_buf[21];
nam_buf[0] = '\0';
if (nam_buf[0] != '\0')
}
/*
* chgreel: Change reel on end-of-media.
*/
static void
{
char vol_tmp[11];
R_cur++;
while (again) {
again = 0;
errno = 0;
"Mount tape %d\nType volume-ID when ready: "), R_cur);
vol_tmp[0] = '\0';
}
errno = 0;
perror("input ERR");
else
perror("output ERR");
}
errno = 0;
again = 1;
continue;
}
again = 1;
continue;
}
switch (dir) {
case INPUT:
perr(0, "Need reel %d, label says reel %d\n",
again = 1;
continue;
}
break;
case OUTPUT:
sleep(2);
errno = 0;
perror("output ERR");
errno = 0;
errno = 0;
sizeof (V_labl)) < 0) {
perr(0, "Cannot re-write header -Try again!\n");
again = 1;
continue;
}
break;
default:
} /* dir */
} /* again */
rprt();
}
/*
* perr: Print error messages.
*/
static void
{
if (severity == 10) {
"\t%d reel(s) completed\n"), --R_cur);
cleanup();
}
if (severity > 0) {
(void) cleanup();
}
}
static void
{
int cnt;
int i;
}
for (i = 0; i < cnt; i++) {
!= DEV_BSIZE) {
}
}
}
static void
{
int cnt;
int i;
errno = 0;
}
for (i = 0; i < cnt; i++) {
!= DEV_BSIZE) {
}
}
}
static char *
{
int i;
int blk;
/*
* is there room for label?
*/
return (nolabel);
/*
* calculate the available blocks for each rotational position
*/
/* void */;
}
static char *
{
char *p;
int i;
p = getfslabel(sb);
return (nolabel);
for (i = 0; *p && i < 6; p++, i++)
;
p++;
return (p);
}