[comp.sources.misc] v02i043: mcat - a cat utility for mmap only devices

rich@oxtrap.UUCP (K. Richard Magill) (02/03/88)

Comp.sources.misc: Volume 2, Issue 43

Submitted-By: "K. Richard Magill" <rich@oxtrap.UUCP>

Archive-Name: mcat


Comp.sources.misc: Volume 2, Issue 43
Submitted-By: "K. Richard Magill" <rich@oxtrap.UUCP>
Archive-Name: mcat

[For Sequents in particular and 4.xBSD with mmap() in general.  ++bsa]

Note: This program uses getopt(3) which doesn't ordinarily exist in
the berkeley universe.  The at&t code for getopt is around and has
been released into the public domain.  (At least, that's my
understanding).

#!/bin/sh
# This is a shell archive, meaning:                              
# 1. Remove everything above the #! /bin/sh line.                
# 2. Save the resulting test in a file.                          
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	mcat.l
#	mcat.c
# This archive created:  Fri Nov 27 18:19:07 EST 1987 by rich@oxtrap
echo extracting mcat.l
sed 's/^X//' >mcat.l << 'END-of-mcat.l'
X.TH MCAT l "27 Nov 87" "local"
X.SH NAME
Xmcat \- cat like program for read/write'ing pmap devices from shell
X.SH SYNOPSIS
X.B mcat
X[-b buffersize] [-i ifile] [-o ofile] [-s] [-v]
X.SH DESCRIPTION
X.I mcat
Xis a program very much like cat or dd that is capable of reading a
Xnon-read(2)'able device, for example, an mmap(2) only device like
Xsequent's pmap devices.  It is capable of copying mmap to mmap,
Xreading and writing onto mmap or reading from mmap and writing.
X.SH OPTIONS
X.PP
X.TP 14
X.B \-b buffersize
Xuse buffersize as the buffer size for read's and write's rather than BUFSIZ.
X.PP
X.TP 14
X.B \-i ifile
Xuse ifile as file name for input rather than stdin.
X.PP
X.TP 14
X.B \-o ofile
Xuse ofile as file name for output rather than stdout.
X.PP
X.TP 14
X.B \-s
Xprint no error messages.  (silent).
X.PP
X.TP 14
X.B \-v
Xprint some log lines.  (verbose).
X.SH BUGS
XDue to a synergy of shell strategy, and balance hardware limitations,
Xyou can not redirect stdout to a pmap device on sequent balance.  (but
Xyou can use -o ofile).
X.SH AUTHOR
XK. Richard Magill - Digital Works Ltd.
X
Xrich@oxtrap.UUCP, rich@sendai.UUCP
END-of-mcat.l
echo extracting mcat.c
sed 's/^X//' >mcat.c << 'END-of-mcat.c'
X/*
X * This file is mcat.c and contains a sort of cat utility for use with
X * pmap devices.  It was originally written on sequent Dynix 2.1.1.
X *
X * to do:
X *	mmap disk files.
X *	mcat multiple files in, out.
X *	-x write at offset x.
X *	trunc old disk files.
X *
X * Original Author: K. Richard Magill Fri Nov 20 16:00:53 EST 1987
X * Last Mod Fri Nov 27 18:06:15 EST 1987, by rich@oxtrap
X *
X *$Header: /u1/rich/bin/src/RCS/mcat.c,v 1.1 87/11/27 18:06:45 rich Exp $
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/file.h>
X#include <sys/ioctl.h>
X#include <sys/mman.h>
X#include <sys/stat.h>
X#include <machine/pmap.h>
X
X#define Perror(s)	{if(Silent==0)perror(s);}
X
Xchar *valloc();
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	char *InBase = ((char *) 0);
X	char *OutBase = ((char *) 0);
X
X	int BufferSize = BUFSIZ;
X	int InPut = fileno(stdin);
X	int OutPut = fileno(stdout);
X	int Silent = 0;
X	int Verbose = 0;
X	int WriteFlags = 0;
X	int c;
X
X	struct pmap_ioc InSize, OutSize;
X	struct stat Readable;
X
X	extern char *optarg;
X	extern int optind;
X
X/*
X * parse args.
X */
X
X	while ((c = getopt(argc, argv, "b:i:o:sv")) != EOF) {
X		switch (c) {
X
X		case 'b':
X			BufferSize = atoi(optind);
X
X			if (Verbose != 0) {
X				(void) fprintf(stderr,
X					       "%s: Using %d byte i/o.\n",
X					       argv[0], BufferSize);
X			} /* verbose */
X
X			break;
X
X		case 'i':
X
X			if ((InPut = open(optarg, O_RDONLY, 0666)) < 0) {
X				Perror("opening input:");
X				exit(1);
X			} /* on error opening for read */
X
X			break;
X
X		case 'o':
X			if (access(optarg, F_OK) == 0) {
X				if (Verbose != 0) {
X					(void) fprintf(stderr, "%s: output exists.\n", argv[0]);
X				} /* verbose */
X
X				if (access(optarg, R_OK) == 0) {
X					if (Verbose != 0) {
X						(void) fprintf(stderr, "%s: output is readable.\n", argv[0]);
X					} /* verbose */
X
X					WriteFlags |= O_RDWR;
X				}
X
X			} else {
X				if (Verbose != 0) {
X					(void) fprintf(stderr, "%s: output does not exist.  creating.\n", argv[0]);
X				} /* verbose */
X
X				WriteFlags = O_CREAT | O_RDWR;
X			}
X
X			if ((OutPut = open(optarg, WriteFlags, 0666)) < 0) {
X				Perror("mcat: opening output");
X				exit(1);
X			} /* on error opening for write */
X
X			break;
X
X		case 's':
X			Silent = 1;
X			break;
X
X		case 'v':
X			Verbose = 1;
X			break;
X
X		case '?':
X		default:
X			if (Silent == 0) {
X				(void) fprintf(stderr, "%s: usage: -b buffer_size -i input_file -o output_file -s -v\n", argv[0]);
X			} /* not silent */
X
X			exit(1);
X
X		} /* switch on switch character */
X	} /* while there are switch characters */
X
X/*
X * I presume that if the ioctl fails, this is not a pmap device and we
X * aren't mapping.  If you know of a better way to check a a descriptor
X * for mmap'ability, (short of chasing the major number through the kernel),
X * let me know.
X */
X
X	if (ioctl(InPut, PMAPIOCGETP, &InSize) == 0) { /* not pmap */
X		if ((InBase = valloc(InSize.pi_size)) == 0) {
X			Perror("valloc'ing output buffer:");
X			exit(1);
X		} /* on error valloc'ing */
X
X		if (mmap(InBase, InSize.pi_size, PROT_READ, MAP_SHARED,
X			 InPut, 0) != 0) {
X			Perror("on error mmap'ing input:");
X			exit(1);
X		} /* on error mmap'ing input */
X
X		if (Verbose != 0) {
X			(void) fprintf(stderr, "%s: mmap'ing input.\n",
X				       argv[0]);
X		} /* verbose */
X
X	} /* not mapped or not mappable */
X
X	if ((ioctl(OutPut, PMAPIOCGETP, &OutSize) == 0)) { /* not mapping */
X		if  ((OutBase = valloc(OutSize.pi_size)) == 0) {
X			Perror("valloc'ing for output buffer:");
X			exit(1);
X		} /* on valloc error */
X
X		if (mmap(OutBase, OutSize.pi_size, PROT_RDWR, MAP_SHARED,
X			 OutPut, 0) != 0) {
X			Perror("mmap'ing output:");
X
X			if (Silent == 0) {
X				(void) fprintf(stderr, "%s: remember you can't redirect output.\n", argv[0]);
X			} /* not silent */
X
X			exit(1);
X		} /* on error mmap'ing output */
X
X		if (Verbose != 0) {
X			(void) fprintf(stderr, "%s: mmap'ing output.\n",
X				       argv[0]);
X		} /* verbose */
X
X	} /* not mapped or not mappable */
X
X	if (InBase != ((char *) NULL)) { /* mapping input */
X		if (OutBase != ((char *) NULL)) { /* and output */
X			bcopy(InBase, OutBase,
X			      (InSize.pi_size < OutSize.pi_size)
X			      ? InSize.pi_size : OutSize.pi_size);
X
X		} else { /* map in, no map out */
X			int ReallyWrote;
X
X			while (InSize.pi_size > 0) {
X				if (BufferSize > InSize.pi_size) {
X					BufferSize = InSize.pi_size;
X				} /* if buffer now holds it all */
X
X				if ((ReallyWrote = write(OutPut, InBase,
X							 BufferSize)) == -1) {
X					Perror("writing output:");
X					exit(1);
X				} /* on error writing */
X
X				InSize.pi_size -= ReallyWrote;
X				InBase += ReallyWrote;
X			}	/* while data to write */
X		} /* if mapping output */
X
X	} else { /* not mapping input */
X
X		if (OutBase != ((char *) NULL)) { /* but mapping output */				int ReallyRead = 1;
X
X			while (ReallyRead != 0 && OutSize.pi_size > 0) {
X				if (BufferSize > OutSize.pi_size) {
X					BufferSize = OutSize.pi_size;
X				} /* if buffer now holds it all */
X
X				if ((ReallyRead = read(InPut, OutBase,
X							 BufferSize)) == -1) {
X					Perror("reading input:");
X					exit(1);
X				} /* on error reading */
X
X				OutSize.pi_size -= ReallyRead;
X				OutBase += ReallyRead;
X			}	/* while data to write */
X
X		} else { /* mapping nothing, should use cat instead */
X			if (Silent == 0) {
X				(void) fprintf(stderr, "%s: not mapping anything.  use cat instead.\n", argv[0]);
X			} /* not silent */
X
X			exit(1);
X		} /* if mapping output */
X	} /* if mapping input */
X
X	exit(0);
X} /* main() */
X
X/*
X * $Log:	mcat.c,v $
X * Revision 1.1  87/11/27  18:06:45  rich
X * Initial revision
X * 
X *
X * Local Variables:
X * comment-column: 0
X * fill-column: 75
X * fill-prefix: " * "
X * mode: c
X * version-control: t
X * End:
X */
X
X/* end of mcat.c */
END-of-mcat.c
exit