/* $Source: /u/mark/src/pax/RCS/pax.c,v $
*
* $Revision: 1.2 $
*
* DESCRIPTION
*
* Pax is the archiver described in IEEE P1003.2. It is an archiver
* which understands both tar and cpio archives and has a new interface.
*
* SYNOPSIS
*
* pax -[cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]
* pax -r [-cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]
* pax -w [-adimuvy] [-b blocking] [-f archive] [-s replstr]...]
* [-t device][-x format][pathname...]
* pax -r -w [-ilmopuvy][-s replstr][pathname...] directory
*
* DESCRIPTION
*
* PAX - POSIX conforming tar and cpio archive handler. This
* program implements POSIX conformant versions of tar, cpio and pax
* archive handlers for UNIX. These handlers have defined befined
* by the IEEE P1003.2 commitee.
*
* COMPILATION
*
* A number of different compile time configuration options are
* available, please see the Makefile and config.h for more details.
*
* AUTHOR
*
* Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
*
*
* Sponsored by The USENIX Association for public distribution.
*
* Copyright (c) 1989 Mark H. Colburn.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice is duplicated in all such
* forms and that any documentation, advertising materials, and other
* materials related to such distribution and use acknowledge that the
* software was developed * by Mark H. Colburn and sponsored by The
* USENIX Association.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Log: pax.c,v $
* Revision 1.2 89/02/12 10:05:17 mark
* 1.2 release fixes
*
* Revision 1.1 88/12/23 18:02:23 mark
* Initial revision
*
*/
#ifndef lint
static char *ident = "$Id: pax.c,v 1.2 89/02/12 10:05:17 mark Exp $";
static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
#endif /* ! lint */
/* Headers */
#define NO_EXTERN
#include "pax.h"
/* Globally Available Identifiers */
char *ar_file; /* File containing name of archive */
char *bufend; /* End of data within archive buffer */
char *bufstart; /* Archive buffer */
char *bufidx; /* Archive buffer index */
char *myname; /* name of executable (argv[0]) */
char **n_argv; /* Argv used by name routines */
int n_argc; /* Argc used by name routines */
int archivefd; /* Archive file descriptor */
int blocking; /* Size of each block, in records */
int gid; /* Group ID */
int head_standard; /* true if archive is POSIX format */
int ar_interface; /* defines interface we are using */
int ar_format; /* defines current archve format */
int mask; /* File creation mask */
int ttyf; /* For interactive queries */
int uid; /* User ID */
int names_from_stdin; /* names for files are from stdin */
OFFSET total; /* Total number of bytes transferred */
short f_access_time; /* Reset access times of input files */
short areof; /* End of input volume reached */
short f_dir_create; /* Create missing directories */
short f_append; /* Add named files to end of archive */
short f_create; /* create a new archive */
short f_extract; /* Extract named files from archive */
short f_follow_links; /* follow symbolic links */
short f_interactive; /* Interactivly extract files */
short f_linksleft; /* Report on unresolved links */
short f_list; /* List files on the archive */
short f_modified; /* Don't restore modification times */
short f_verbose; /* Turn on verbose mode */
short f_link; /* link files where possible */
short f_owner; /* extract files as the user */
short f_pass; /* pass files between directories */
short f_newer; /* append files to archive if newer */
short f_disposition; /* ask for file disposition */
short f_reverse_match; /* Reverse sense of pattern match */
short f_mtime; /* Retain file modification time */
short f_unconditional; /* Copy unconditionally */
time_t now = 0; /* Current time */
uint arvolume; /* Volume number */
uint blocksize = BLOCKSIZE; /* Archive block size */
FILE *msgfile; /* message outpu file stdout/stderr */
Replstr *rplhead = (Replstr *)NULL; /* head of replstr list */
Replstr *rpltail; /* pointer to tail of replstr list */
/* Function Prototypes */
#ifdef __STDC__
static void usage(void);
static OFFSET pax_optsize(char *);
#else /* !__STDC__ */
static void usage();
static OFFSET pax_optsize();
#endif /* __STDC__ */
/* main - main routine for handling all archive formats.
*
* DESCRIPTION
*
* Set up globals and call the proper interface as specified by the user.
*
* PARAMETERS
*
* int argc - count of user supplied arguments
* char **argv - user supplied arguments
*
* RETURNS
*
* Returns an exit code of 0 to the parent process.
*/
#ifdef __STDC__
int main(int argc, char **argv)
#else
int main(argc, argv)
int argc;
char **argv;
#endif
{
/* strip the pathname off of the name of the executable */
if ((myname = strrchr(argv[0], '/')) != (char *)NULL) {
myname++;
} else {
myname = argv[0];
}
/* set upt for collecting other command line arguments */
name_init(argc, argv);
/* get all our necessary information */
mask = umask(0);
uid = getuid();
gid = getgid();
now = time((time_t *) 0);
/* open terminal for interactive queries */
ttyf = open_tty();
if (strcmp(myname, "tar")==0) {
do_tar(argc, argv);
} else if (strcmp(myname, "cpio")==0) {
do_cpio(argc, argv);
} else {
do_pax(argc, argv);
}
exit(0);
/* NOTREACHED */
}
/* do_pax - provide a PAX conformant user interface for archive handling
*
* DESCRIPTION
*
* Process the command line parameters given, doing some minimal sanity
* checking, and then launch the specified archiving functions.
*
* PARAMETERS
*
* int ac - A count of arguments in av. Should be passed argc
* from main
* char **av - A pointer to an argument list. Should be passed
* argv from main
*
* RETURNS
*
* Normally returns 0. If an error occurs, -1 is returned
* and state is set to reflect the error.
*
*/
#ifdef __STDC__
int do_pax(int ac, char **av)
#else
int do_pax(ac, av)
int ac; /* argument counter */
char **av; /* arguments */
#endif
{
int c;
char *dirname;
Stat st;
/* default input/output file for PAX is STDIN/STDOUT */
ar_file = "-";
/*
* set up the flags to reflect the default pax inteface. Unfortunately
* the pax interface has several options which are completely opposite
* of the tar and/or cpio interfaces...
*/
f_unconditional = 1;
f_mtime = 1;
f_dir_create = 1;
f_list = 1;
blocksize = 0;
blocking = 0;
ar_interface = PAX;
ar_format = TAR; /* default interface if none given for -w */
msgfile=stdout;
while ((c = getopt(ac, av, "ab:cdf:ilmoprs:t:uvwx:y")) != EOF) {
switch (c) {
case 'a':
f_append = 1;
f_list = 0;
break;
case 'b':
if ((blocksize = pax_optsize(optarg)) == 0) {
fatal("Bad block size");
}
break;
case 'c':
f_reverse_match = 1;
break;
case 'd':
f_dir_create = 0;
break;
case 'f':
if (blocksize == 0) {
blocking = 1;
blocksize = 1 * BLOCKSIZE;
}
ar_file = optarg;
break;
case 'i':
f_interactive = 1;
break;
case 'l':
f_link = 1;
break;
case 'm':
f_mtime = 0;
break;
case 'o':
f_owner = 1;
break;
case 'p':
f_access_time = 1;
break;
case 'r':
if (f_create) {
f_create = 0;
f_pass = 1;
} else {
f_list = 0;
f_extract = 1;
}
msgfile=stderr;
break;
case 's':
add_replstr(optarg);
break;
case 't':
if (blocksize == 0) {
blocking = 1;
blocksize = 10 * BLOCKSIZE;
}
ar_file = optarg;
break;
case 'u':
f_unconditional = 1;
break;
case 'v':
f_verbose = 1;
break;
case 'w':
if (f_extract) {
f_extract = 0;
f_pass = 1;
} else {
f_list = 0;
f_create = 1;
}
msgfile=stderr;
break;
case 'x':
if (strcmp(optarg, "ustar") == 0) {
ar_format = TAR;
} else if (strcmp(optarg, "cpio") == 0) {
ar_format = CPIO;
} else {
usage();
}
break;
case 'y':
f_disposition = 1;
break;
default:
usage();
}
}
if (blocksize == 0) {
blocking = 1;
blocksize = blocking * BLOCKSIZE;
}
buf_allocate((OFFSET) blocksize);
if (f_extract || f_list) {
open_archive(AR_READ);
get_archive_type();
read_archive();
} else if (f_create) {
if (optind >= n_argc) {
names_from_stdin++; /* args from stdin */
}
open_archive(AR_WRITE);
create_archive();
} else if (f_append) {
open_archive(AR_APPEND);
get_archive_type();
append_archive();
} else if (f_pass && optind < n_argc) {
dirname = n_argv[--n_argc];
if (LSTAT(dirname, &st) < 0) {
fatal(strerror());
}
if ((st.sb_mode & S_IFMT) != S_IFDIR) {
fatal("Not a directory");
}
if (optind >= n_argc) {
names_from_stdin++; /* args from stdin */
}
pass(dirname);
} else {
usage();
}
return (0);
}
/* get_archive_type - determine input archive type from archive header
*
* DESCRIPTION
*
* reads the first block of the archive and determines the archive
* type from the data. If the archive type cannot be determined,
* processing stops, and a 1 is returned to the caller. If verbose
* mode is on, then the archive type will be printed on the standard
* error device as it is determined.
*
* FIXME
*
* be able to understand TAR and CPIO magic numbers
*/
#ifdef __STDC__
void get_archive_type(void)
#else
void get_archive_type()
#endif
{
if (ar_read() != 0) {
fatal("Unable to determine archive type.");
}
if (strncmp(bufstart, "070707", 6) == 0) {
ar_format = CPIO;
if (f_verbose) {
fputs("CPIO format archive\n", stderr);
}
} else if (strncmp(&bufstart[257], "ustar", 5) == 0) {
ar_format = TAR;
if (f_verbose) {
fputs("USTAR format archive\n", stderr);
}
} else {
ar_format = TAR;
}
}
/* pax_optsize - interpret a size argument
*
* DESCRIPTION
*
* Recognizes suffixes for blocks (512-bytes), k-bytes and megabytes.
* Also handles simple expressions containing '+' for addition.
*
* PARAMETERS
*
* char *str - A pointer to the string to interpret
*
* RETURNS
*
* Normally returns the value represented by the expression in the
* the string.
*
* ERRORS
*
* If the string cannot be interpretted, the program will fail, since
* the buffering will be incorrect.
*
*/
#ifdef __STDC__
static OFFSET pax_optsize(char *str)
#else
static OFFSET pax_optsize(str)
char *str; /* pointer to string to interpret */
#endif
{
char *idx;
OFFSET number; /* temporary storage for current number */
OFFSET result; /* cumulative total to be returned to caller */
result = 0;
idx = str;
for (;;) {
number = 0;
while (*idx >= '0' && *idx <= '9')
number = number * 10 + *idx++ - '0';
switch (*idx++) {
case 'b':
result += number * 512L;
continue;
case 'k':
result += number * 1024L;
continue;
case 'm':
result += number * 1024L * 1024L;
continue;
case '+':
result += number;
continue;
case '\0':
result += number;
break;
default:
break;
}
break;
}
if (*--idx) {
fatal("Unrecognizable value");
}
return (result);
}
/* usage - print a helpful message and exit
*
* DESCRIPTION
*
* Usage prints out the usage message for the PAX interface and then
* exits with a non-zero termination status. This is used when a user
* has provided non-existant or incompatible command line arguments.
*
* RETURNS
*
* Returns an exit status of 1 to the parent process.
*
*/
#ifdef __STDC__
static void usage(void)
#else
static void usage()
#endif
{
fprintf(stderr, "Usage: %s -[cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]\n",
myname);
fprintf(stderr, " %s -r [-cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]\n",
myname);
fprintf(stderr, " %s -w [-adimuvy] [-b blocking] [-f archive] [-s replstr]\n [-t device] [-x format] [pathname...]\n",
myname);
fprintf(stderr, " %s -r -w [-ilmopuvy] [-s replstr] [pathname...] directory\n",
myname);
exit(1);
}
|