Ultrix-3.1/src/cmd/ltf/ltf.c
/**********************************************************************
* Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. *
* All Rights Reserved. *
* Reference "/usr/src/COPYRIGHT" for applicable restrictions. *
**********************************************************************/
#ifndef lint
static char *sccsid = "@(#)ltf.c 3.0 (ULTRIX) 4/21/86";
#endif lint
/**/
/*
* Summary of the modules that comprise the Labeled Tape Facility,
* (LTF) in alpha-numeric order.
*
*
* NAME Function
* ------------ ----------------------------------------
*
* filenames.c Contains the routines that deal with
* file-name conversions.
*
* filetype.c Contains the logic to determine the "type"
* of Ultrix disk file being processed.
*
* initvol.c Contains the logic to initialize the
* output volume.
*
* ltf.c The main-line logic of the LTF. Interprets
* the command line and calls the appropriate
* sub-module to deal with input or output.
*
* ltfdefs.h Contains the definitions of Global
* constants, external declarations,
* and data structures.
*
* NOTE: It also "includes" the system
* include files that are required
* by all LTF modules so that each
* module need only "include" ltfdefs.h
* to bring in all required system
* includes, correct declarations
* and variable definitions.
*
* ltferrs.h Contains the error message macros and error
* messages themselves.
*
* ltfvars.c Contains the declarations of the Global
* variables used by the LTF.
*
* makefile The MAKEFILE for the LTF.
*
* mstrcmp.c Contains the logic to compare file names.
* ie. Interprets and expands meta-characters
* allowed in LTF commands. ("*", "?", etc..)
*
* odm.c Contains the routines that deal with physical
* output device manipulations.
* Centralizes the "ioctl" logic that is used on
* Ultrix-32, 32m, 11, etc..
*
* putdir.c Contains the logic to output directory files
* for the LTF.
*
* putfile.c Contains the routines that output files to
* the given volume.
*
* README.1 Important documentation concerning the design
* and implementation of the LTF. Includes file
* and ANSI volume/label diagrams.
*
* scantape.c Scans the input volume for TABLE
* and EXTRACT functions.
*
* xtractf.c Extracts (reads) files from the input volume.
*/
/**/
/*
* GENERAL COMPILE PATH
* -----------------------
*
* source / GLOBAL defs & externals
* \ /
* +-------+ +--------------------------+
* | x.c |--#includes--->| ltfdefs.h |
* +-------+ +--------------------------+
* | | |
* | #includes #includes
* | | |
* V V V
* +-------+ +-----------+ +------------------+
* | x.o | | ltferrs.h | | (system.h |
* +-------+ +-----------+ | files) |
* / +------------------+
* object /
*
*
* LINKAGE
* -------
*
* The object modules produced by the above compilations
* (see makefile) are linked together producing the
* executable file --> ltf
*/
/**/
/*
*
* File name:
*
* ltf.c
*
* Source file description:
*
* This module is the main-line logic of/for the
* Labeled Tape Facility (LTF).
*
*
* Functions:
*
* main() The main-line logic. "main" parses the
* command line arguments. If any errors are
* detected, an appropriate message is output &
* an exit back to the system is taken.
* If a valid command is entered, control is passed
* to the appropriate input -or- output
* top-level logic module.
*
*
* expnum() Expands a numeric character string into an
* integer with optional "block" or "k" value
* multiplication.
*
* response() Waits for the user to press the RETURN
* before proceeding
*
* showhelp() Displays help messages explaining briefly the
* usage of the switches of ltf
*
* usage() Outputs the desired command format when the
* occasion arises.
*
* Usage:
*
* General command format is:
*
* ltf function(s) -qualifiers [ filename ] ... [ filename ]
*
* The LTF reads & writes ANSI compatible tape formats.
*
*
* Compile:
*
* cc -O -c ltf.c <- For Ultrix-32/32m
*
* cc CFLAGS=-DU11-O ltf.c <- For Ultrix-11
*
*
* In point of fact, the complete ltf can only be built
* by its' makefile as the facility is in multi-module
* format as opposed to single source.
*
*
* Modification history:
* ~~~~~~~~~~~~~~~~~~~~
*
* revision comments
* -------- -----------------------------------------------
* 01.0 04-Apr-85 Ray Glaser
* Create orginal version.
*
* 01.1 22-Aug-85 Suzanne Logcher
* Reorganize ltf.c to look more like tar.
*
* 01.2 28-Oct-85 Suzanne Logcher
* Add tar's magtape defaults
*/
/**/
/*
* -> Local defines "required for / defined by" this module
*
* NOTE: This statement must come before the local
* includes to correctly define the compilation
* of GLOBALS..
*
*/
#define MAINC /* So that we don't doubly define message
* strings and other global variables when
* we compile/link sub-modules.
*/
/*
* -> Local includes
*/
#include "ltfdefs.h" /* Common GLOBAL constants & structs */
/**/
/*
*
* Function:
*
* main
*
* Function Description:
*
* Processes the command line, rejects invalid commands, and
* calls appropriate top-level routine for input/output.
*
* Arguments:
*
* int argc Argument count
* char *argv[] Pointer to array of pointers to args
*
*
* Return values:
*
* n/a
*
*
* Side Effects:
*
* n/a
*
*/
main (argc, argv)
int argc;
char *argv[];
{
/*
* -> Local variables
*/
char *a; /* pointer to *argv */
int dumpflag = 0; /* Flags word used to set up
* f_flags in filestat structure
* indicating dump mode of this
* file */
int iflag = 0; /* The I option. iflag = 0 if
* no arguments othan ther the
* command-line arguments are
* to be processed. iflag = -1
* if the standard input is to
* be read for more file names.
* iflag = 1 if a file
* containing additional file
* arguments is given. */
FILE *ifp; /* File pointer to inputfile
* (if iflag = 1) */
char inputfile[MAXPATHLEN+1]; /* If iflag = 1, inputfile is
* the file containing additional
* file arguments. If iflag = -1,
* inputfile[0] = '-' to indicate
* that the user is to be
* prompted for the other file
* names; otherwise, inputfile[0] = 0
* for no prompting. */
int mag = 0; /* Flag to check if f qualifier used */
char magtape[MAXPATHLEN+1]; /* magtape name from switches */
char *nmbr1; /* Temporary variable for use with
* strings read in to be converted to
* numbers */
int pflag = 0; /* Flag to check that P is only used
* with EXTRACT */
int ret = TRUE; /* Boolean to check success of
* rec_file */
char unit = -1; /* Unit number of named tape device */
/**/
/*------*\
Code
\*------*/
/* Set warning on if all links to a file are not resolved */
Rep_misslinks = NO;
for (i=0; i < BUFSIZE; i++)
Spaces[i] = ' ';
/* So that error routines know the name of this program
*/
Progname = argv[0];
if (--argc <= 0)
usage();
else {
Func = NO;
argc--;
argv++;
for (a = *argv++; *a; a++) {
switch(*a) {
/* Optional '-' in front of functions
*/
case '-':
break;
/* List a help message with all
* functions, switches, and qualifiers
*/
case 'H':
showhelp();
/* Create a new volume (output)
* of files and directories.
*/
case 'c':
if (Func != NO) {
PERROR "\n%s: %s\n", Progname, CONFF);
usage();
}
Func = CREATE;
break;
/* Provide a table of contents
* (index) of an input volume.
*/
case 't':
if (Func != NO) {
PERROR "\n%s: %s\n", Progname, CONFF);
usage();
}
Func = TABLE;
break;
/* Extract (read in) files and
* and directories from an
* input volume.
*/
case 'x':
if (Func != NO) {
PERROR "\n%s: %s\n", Progname, CONFF);
usage();
}
Func = EXTRACT;
break;
/* Output ANSI version 3 volume
*/
case 'a':
Ansiv = '3';
break;
/* Select 6250 GCR device
*/
case 'g':
#ifdef U11
strcpy(magtape, "/dev/rgt0");
mag = 1;
#endif
break;
/* Output the file a symbolic link
* points to instead of the link file
*/
case 'h':
Nosym = TRUE;
break;
/* Select TK50 device
*/
case 'k':
#ifdef U11
strcpy(magtape, "/dev/rtk0");
mag = 1;
#endif
break;
/* Select 800 bpi tape
*/
case 'n':
strcpy(magtape, "/dev/rmt0");
mag = 1;
break;
/* Omit directory blocks from output
* volume
*/
case 'o':
Nodir = TRUE;
break;
/* No HDR3 switch will not output
* optional headers 3 thru 9
*/
case 'O':
Noheader3 = TRUE;
break;
/* Permission flag, set when extracting
* files and super user, will change
* owner and mode to info on tape volume
*/
case 'p':
permission = TRUE;
break;
/* Verbose - give the user more
* information about what is going
* to/from a volume, not including
* directories.
*/
case 'v':
Verbose = YES;
break;
/* Big Verbose also provides information
* about directory files on the volume
* as well as the normal Verbose
* information about files.
*/
case 'V':
Verbose = Dverbose = YES;
break;
/* Set warning on if a file of the same
* name exists
*/
case 'w':
Warning = YES;
break;
/* Select an alternate unit number.
*/
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
unit = *a;
break;
/* Set new blocksize by input
*/
case 'B':
if (*argv == 0) {
PERROR "\n%s: %s\n", Progname, NOBLK);
usage();
}
nmbr1 = *argv;
Blocksize = expnum(nmbr1);
if (error_status) {
PERROR "\n%s: %s %s\n\n", Progname, INVNF, nmbr1);
exit(FAIL);
}
if (Blocksize > MAXBLKWRT || Blocksize < MINBLKSIZE) {
PERROR "\n%s: %s %d%s\n\n", Progname, INVBS, MAXBLKWRT, BYTES);
exit(FAIL);
}
*argv++;
argc--;
break;
/* Get devicefilename argument
*/
case 'f':
if (*argv == 0) {
PERROR "\n%s: %s\n", Progname, NOFIL);
usage();
}
else
/*
* The name following 'f' is used
* literally as the tape device name
*/
if (strlen(*argv) < MAXNAMLEN)
strcpy(magtape, *argv++);
else {
PERROR "\n%s: %s %s\n", Progname, FNTL, a);
exit(FAIL);
}
mag = 2;
argc--;
break;
/* Get filename of list of files to
* be operated on or by STDIN
*/
case 'I':
if (*argv == 0) {
PERROR "\n%s: %s\n", Progname, NOINP);
usage();
}
if (strlen(*argv) < MAXNAMLEN)
strcpy(inputfile, *argv++);
else {
PERROR "\n%s: %s %s\n", Progname, FNTL, a);
exit(FAIL);
}
if (*inputfile == '-')
iflag = -1;
else {
iflag = 1;
if (!(ifp = fopen(inputfile, "r"))) {
PERROR "\n%s: %s %s\n\n", Progname,
CANTOPEN, inputfile);
exit(FAIL);
}
}/*F if *inputfile == '-' */
argc--;
break;
/* Get new volume identification
*/
case 'L':
if (*argv == 0) {
PERROR "\n%s: %s\n", Progname, NOVOL);
usage();
}
/* Make sure it is not too long
*/
if (strlen(*argv) > 6) {
PERROR "\n%s: %s\n", Progname, VOLIDTL);
exit(FAIL);
}
strcpy(Volid,*argv++);
if (!filter_to_a(Volid,REPORT_ERRORS)) {
PERROR "\n%s: %s", Progname, INVVID1);
PERROR "\n%s: %s %s\n\n", Progname, INVVID2, Volid);
exit(FAIL);
}
argc--;
break;
/* Position to an ANSI file sequence
* number before beginning requested
* operations.
*/
case 'P':
if (*argv == 0) {
PERROR "\n%s: %s\n", Progname, NOPOS);
usage();
}
nmbr1 = *argv;
while ((isdigit(*nmbr1)) || (*nmbr1 == ',') || (*nmbr1 == '-'))
nmbr1++;
if (*nmbr1 != '\0') {
PERROR "\n%s: %s %s\n\n", Progname, INVNF, *argv);
exit(FAIL);
}
sscanf(*argv++, "%d,%d", &Seqno, &Secno);
if (Seqno <= 0) {
PERROR "\n%s: %s %d\n\n", Progname, INVPN, Seqno);
exit(FAIL);
}
if (Secno <= 0) {
PERROR "\n%s: %s %d\n\n", Progname, INVPS, Secno);
exit(FAIL);
}
++pflag;
argc--;
break;
/* Set new record length
*/
case 'R':
if (*argv == 0) {
PERROR "\n%s: %s\n", Progname, NOREC);
usage();
}
nmbr1 = *argv;
Reclength = expnum(nmbr1);
if (error_status) {
PERROR "\n%s: %s %s\n\n", Progname, INVNF, nmbr1);
exit(FAIL);
}
if (Reclength > MAXRECSIZE || Reclength < 1) {
PERROR "\n%s: %s %d%s\n\n", Progname, INVRS, MAXRECSIZE, BYTES);
exit(FAIL);
}
*argv++;
argc--;
break;
/* Else error
*/
default:
PERROR "\n%s: %s %c\n", Progname, UNQ, *a);
usage();
}/*E switch *a */
}/* for */
}/*T if --argc > 0 */
/**/
/* +--> Begin processing the requested function(s) ..*/
if (Func == NO) {
PERROR "\n%s: %s\n", Progname, NOFUNC);
usage();
}
if (permission) {
if ((i = getuid()) > 0) {
PERROR "\n%s: %s %d\n", Progname, NOTSU, i);
permission = FALSE;
}
else
if (Func != EXTRACT) {
PERROR "\n%s: %s\n", Progname, CANTPER);
permission = FALSE;
}
}
if (mag > 0) {
strcpy(Magtdev, magtape);
if (mag == 1 && unit != -1)
Magtdev[8] = unit;
}
Tape = tape(Magtdev); /* Decide if using tape and set flag */
rew(0);
if (Func == TABLE || Func == EXTRACT) {
if (Nodir)
Dverbose = NO;
dumpflag = 0;
for ( ; argc > 0; argc--, argv++)
rec_args(*argv, dumpflag);
if (iflag == 1)
ret = rec_file(ifp, iflag, "");
else
if (iflag == -1)
ret = rec_file(stdin, iflag, "");
if (ret)
scantape();
else
printf("\n");
}/*T if Func == TABLE || Func == EXTRACT */
else { /* if Func == CREATE */
/* If we are to create a new volume, Magtdev will be opened
* for writing in initvol().
*/
if (pflag != 0) {
PERROR "\n%s: %s\n\n", Progname, INVPNUSE);
}
if (iflag == 0 && argc == 0) {
PERROR "\n%s: %s\n", Progname, NOARGS);
usage();
}
if (Func == WRITE) {
if (iflag == 1)
fclose(ifp);
#if 0
writetp(argc, argv, iflag, inputfile);
#endif
}/*E if Func = WRITE */
else
if (Func == CREATE) {
if (iflag == 1)
fclose(ifp);
/* Go initialize the "volume" on the output
* device of choice. We won't be coming back.
*/
printf("\n");
initvol(argc, argv, iflag, inputfile);
}/*T if Func == CREATE */
}/*F if Func == TABLE || Func == EXTRACT */
}/*E main() */
/**/
/*
*
* Function:
*
* expnum
*
* Function Description:
*
* Expand a numeric character string into an integer
* multiple of the format expressed. ie.. Allow the user
* to input a value in blocks (or k) and we convert it
* to the real number of bytes implied.
*
* For example -> 10b = ten 512 byte blocks
* -or- 3k = three 1024 byte blocks
*
* Arguments:
*
* char *numstring Pointer to the null terminated numeric
* character string.
* int error_status TRUE indicates invalid numeric string
* FALSE indicates no error
*
* Return values:
*
* Returns a numeric value if the conversion was valid.
*
*
*
*/
/* moved expnum() into filenames.c to fit overlay version */
/* moved usage() into filenames.c */
/* moved showhelp() into filenames.c */
/**/
/*
*
* Function:
*
* response()
*
* Function Description:
*
* Waits for a response of RETURN until exiting
*
* Arguments:
*
* n/a
*
* Return values:
*
* none
*
* Side Effects:
*
* none
*
*/
response()
{
/*------*\
Code
\*------*/
ch = getchar();
if (ch != '\n')
while (getchar() != '\n')
;
else
ch = 'n';
return(ch);
}/* E response */
/**\\**\\**\\**\\**\\** EOM ltf.c **\\**\\**\\**\\**\\*/
/**\\**\\**\\**\\**\\** EOM ltf.c **\\**\\**\\**\\**\\*/