v15i051: A cat(1) for mmap'able devices

Rich Salz rsalz at uunet.uu.net
Thu Jun 9 05:47:48 AEST 1988


Submitted-by: "K. Richard Magill" <oxtrap!rich>
Posting-number: Volume 15, Issue 51
Archive-name: mcat2

[  I haven't tried this, but I did splice the makefile into the shar.  -r$  ]

This is a program that works like cat but can read or write mmap'able
devices like sequent's pmap(4).  I haven't tried it yet, but it should
also work on devices like sun frame buffers.  The version I posted
earlier worked on dynix 2.1.1 but apparently 3.0.4 can't write/send(2)
from mmap'd memory, (or at least pmap devices).

#!/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:
#	makefile mcat.l mcat.c
echo extracting makefile
sed 's/^X//' >makefile << 'END-of-makefile'
all:		mcat mcat.l
mcat:	mcat.c
	$(CC) -o mcat $(CFLAGS) mcat.c
install:	all
	@echo install according to local convention
END-of-makefile
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 at oxtrap.UUCP, rich at 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 Mon Mar 21 00:31:18 EST 1988, by rich at oxtrap
X *
X *$Header: /u1/rich/bin/src/RCS/mcat.c,v 1.2 88/03/21 00:42:41 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
Xextern char *optarg;
Xextern int optind;
X
Xchar *malloc();
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
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(optarg);
X
X			if (Verbose != 0) {
X				(void) fprintf(stderr, "%s: Using %d byte i/o.\n", 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, (char *) &InSize) == 0) { /* not pmap */
X		if ((InBase = valloc((unsigned) InSize.pi_size)) == 0) {
X			Perror("valloc'ing output buffer:");
X			exit(1);
X		} /* on error valloc'ing */
X
X		if (mmap(InBase, (int) InSize.pi_size, PROT_READ, MAP_SHARED, 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, (char *) &OutSize) == 0)) { /* not mapping */
X		if  ((OutBase = valloc((unsigned) OutSize.pi_size)) == 0) {
X			Perror("valloc'ing for output buffer:");
X			exit(1);
X		} /* on valloc error */
X
X		if (mmap(OutBase, (int) OutSize.pi_size, PROT_RDWR, MAP_SHARED, 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			(void) bcopy(InBase, OutBase, (unsigned) ((InSize.pi_size < OutSize.pi_size) ? InSize.pi_size : OutSize.pi_size));
X		} else { /* map in, no map out */
X			int ReallyWrote;
X
X			OutBase = malloc((unsigned) BufferSize);
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				(void) bcopy(InBase, OutBase, (unsigned) BufferSize); /* silly new limitation */
X
X				if ((ReallyWrote = write(OutPut, OutBase, BufferSize)) != BufferSize) {
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 */
X			int ReallyRead = 1;
X
X			InBase = malloc((unsigned) BufferSize);
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, InBase, BufferSize)) == -1) {
X					Perror("reading input:");
X					exit(1);
X				} /* on error reading */
X
X				(void) bcopy(InBase, OutBase, (unsigned) ReallyRead); 
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.2  88/03/21  00:42:41  rich
X * now double bufferred to cover dynix 3.0.4 limitation.
X * 
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: 130
X * fill-prefix: " * "
X * mode: c
X * version-control: t
X * End:
X */
X
X/* end of mcat.c */
END-of-mcat.c
exit

-- 
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.



More information about the Comp.sources.unix mailing list