Newsgroups: comp.sources.misc
From: Chip Rosenthal <chip@chinacat.unicom.com>
Subject:  v22i027:  prtscrn - screen dump utility for SCO UNIX/XENIX, Part01/01
Message-ID: <1991Aug18.004439.14517@sparky.IMD.Sterling.COM>
X-Md4-Signature: a8f22b02e4d97730d2d486d63939d9f7
Date: Sun, 18 Aug 1991 00:44:39 GMT
Approved: kent@sparky.imd.sterling.com

Submitted-by: Chip Rosenthal <chip@chinacat.unicom.com>
Posting-number: Volume 22, Issue 27
Archive-name: prtscrn/part01
Environment: SCO

`prtscrn' grabs the contents of a console MultiScreen(tm) on SCO
UNIX and XENIX systems, and sends them to stdout.

To dump the contents of /dev/tty01 to a file, you'd run:

	prtscrn -1 >filename

When compiling, be sure you specify either -DSCO_UNIX or -DSCO_XENIX.

#! /bin/sh
# this is a "shar" archive - run through "/bin/sh" to extract 3 files:
#   README prtscrn.c prtscrn.1
# Wrapped by chip@chinacat on Sat Aug 17 18:30:56 CDT 1991
# Unpacking this archive requires:  sed test wc (possibly mkdir)
# Existing files will not be clobbered unless "-c" is specified on the cmd line.
if test -f README -a "$1" != "-c" ; then
    echo "README: file exists - will not be overwritten"
else
    echo "x - README (file 1 of 3, 1250 chars)"
    sed -e 's/^X//' << 'END_OF_FILE_README' > README
X`prtscrn' grabs the contents of a console MultiScreen(tm) on SCO
XUNIX and XENIX systems.
X
XTo dump the contents of /dev/tty01 to a file, you'd run:
X
X	prtscrn -1 >filename
X
XWhen compiling, you need to define either SCO_UNIX or SCO_XENIX.
X
XSince this utility gropes through /dev/console, /dev/kmem, and the
Xkernel (/xenix or /unix), it needs to be installed setuid.  Unfortunately,
Xgiven the places it needs to grope, I don't think you'll get away with
Xanything less than setting the ownership to `root'.  The privileges
Xare renounced once `prtscrn' has the information it needs and *before*
Xit attempts to grab the requested screen.  Therefore, this utility
Xwill not access to a screen to which the user does not have permissions.
X
XTherefore, to build this you need to:
X
X	cc -O -DSCO_UNIX -o prtscrn prtscrn.c	(or -DSCO_XENIX)
X	cp prtscrn /usr/bin/prtscrn
X	chown root /usr/bin/prtscrn
X	chmod 4711 /usr/bin/prtscrn
X
XI believe there is a bug in the SCO UNIX console driver which this
Xprogram runs into.  A character gets munged in the screen printing
Xsequence, so after you run this program you might find the character
Xin the bottom-left corner of the screen to be a space.
X
XChip Rosenthal
X<chip@chinacat.Unicom.COM>
X
X@(#) README 1.1 91/08/17 18:29:09
X
END_OF_FILE_README
    size="`wc -c < README`"
    if test 1250 -ne "$size" ; then
	echo "README: extraction error - got $size chars"
    fi
fi
if test -f prtscrn.c -a "$1" != "-c" ; then
    echo "prtscrn.c: file exists - will not be overwritten"
else
    echo "x - prtscrn.c (file 2 of 3, 6099 chars)"
    sed -e 's/^X//' << 'END_OF_FILE_prtscrn.c' > prtscrn.c
X#ifndef lint
Xstatic char SCCSID[] = "@(#) prtscrn.c 1.3 91/08/17 18:28:53";
X#endif
X
X/*
X * prtscrn - SCO UNIX/XENIX screen dump utility.
X *
X * This must be compiled with either SCO_XENIX or SCO_UNIX defined.
X *
X * This utility will grab the contents of another console multiscreen
X * (permissions willing) and send it to the stdout of the process
X * running on the invoking screen.
X *
X * Edit at tabstops=4.
X *
X * Chip Rosenthal, Unicom Systems Development, Inc.
X * <chip@chinacat.unicom.com>
X */
X
X#define USAGE	"usage: %s -screen_num\n"
X
X#include <stdio.h>
X#include <ctype.h>
X#include <string.h>
X#include <fcntl.h>
X#include <sys/types.h>
X
X#ifdef SCO_XENIX
X#include <sys/a.out.h>
X#include <sys/ioctl.h>
X#include <sys/vid.h>
X#define KERNEL	"/xenix"
X#define KBGRP	"_cn_kbgr"
X#endif /*SCO_XENIX*/
X
X#ifdef SCO_UNIX
X#include <nlist.h>
X#include <sys/vid.h>
X#include <sys/console.h>
X#define KERNEL	"/unix"
X#define KBGRP	"cn_kbgrp"
X#define SCO_CONSOLE_BUG
X#endif /*SCO_UNIX*/
X
X#ifndef KERNEL
X#error you need to define either SCO_UNIX or SCO_XENIX
X#endif
X
X#ifdef strerror	/* so much for sqa */
X# undef strerror
X# define strerror(n) (sys_errlist[n])
X#endif
X
X#define MAXCOLS	256
X
Xchar *Progname;
Xchar *Kernel = KERNEL;
X
Xstruct {
X	int mode;
X	int ncols;
X	int nrows;
X} Disptab[] = {
X	{ M_B40x25,			40, 25 },
X	{ M_C40x25,			40, 25 },
X	{ M_ENH_B40x25,		40, 25 },
X	{ M_ENH_C40x25,		40, 25 },
X	{ M_VGA_40x25,		40, 25 },
X	{ M_B80x25,			80, 25 },
X	{ M_C80x25,			80, 25 },
X	{ M_EGAMONO80x25,	80, 25 },
X	{ M_ENH_B80x25,		80, 25 },
X	{ M_ENH_C80x25,		80, 25 },
X	{ M_VGA_80x25,		80, 25 },
X	{ M_VGA_M80x25,		80, 25 },
X	{ M_MCA_MODE,		80, 25 },
X	{ M_ENH_B80x43,		80, 43 },
X	{ M_ENH_C80x43,		80, 43 },
X	{ -1,				0,   0 }
X};
X
Xstruct nlist nl[] = { 
X	{ KBGRP, },
X	{ "", },
X};
X
Xchar *strtrim();
X
Xextern int errno;
Xextern char *sys_errlist[];
X
X
Xvoid setscreen(fd, scrnum)
Xint fd, scrnum;
X{
X	char buf[8];
X#ifdef SCO_CONSOLE_BUG
X	/*
X	 * There is a bug in the SCO3.2v2.0 console driver.  When you use the
X	 * screen switch escape, a character gets munched.  We need to provide
X	 * a byte of fodder to preserve the switch screen sequence.
X	 */
X	write(fd, " ", 1);
X#endif
X	sprintf(buf, "\033[%dz", scrnum-1);
X	write(fd, buf, strlen(buf));
X}
X
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	char *disp_mem;			/* pointer to video display memory		*/
X	char scrname[64];		/* pathname to selected screen			*/
X	char linebuf[MAXCOLS+1];/* space to hold a lineful of chars		*/
X	int curr_scrn;			/* screen initially being displayed		*/
X	int sel_scrn;			/* selected screen to dump				*/
X	int disp_mode;			/* display mode of selected screen		*/
X	int num_cols;			/* number of columns in selected screen	*/
X	int num_rows;			/* number of rows in selected screen	*/
X	int fd_cons;			/* file descriptor for console output	*/
X	struct kbgrp kb;		/* kernel struct with curr screen info	*/
X	int row, col, fd, i;
X
X	Progname = argv[0];
X
X	if (argc != 2 && *argv[1] != '-') {
X		fprintf(stderr, USAGE, Progname);
X		exit(1);
X	}
X
X	/*
X	 * See which screen we want to dump.
X	 */
X	sel_scrn = atoi(argv[1]+1);
X	if (sel_scrn < 1 || sel_scrn > MAXSCRN) {
X		fprintf(stderr, "%s: bad screen number specified\n", Progname);
X		exit(1);
X	}
X	sprintf(scrname, "/dev/tty%02d", sel_scrn);
X
X	/*
X	 * Open up the current screen.
X	 */
X	if ((fd_cons = open("/dev/console", O_RDWR)) < 0) {
X		fprintf(stderr, "%s: open(/dev/console) failed [%s]\n",
X			Progname, strerror(errno));
X		exit(1);
X	}
X
X	/*
X	 * Rummage around in the kernel to determine currently active multiscreen.
X	 * Thanks to Karl Bunch <karl@ttank.com> for the idea on how to do this.
X	 */
X	if (nlist(Kernel, nl) != 0) {
X		fprintf(stderr, "%s: nlist(%s) failed [%s]\n",
X			Progname, Kernel, strerror(errno));
X		exit(1);
X	}
X	if (nl[0].n_value == 0) {
X		fprintf(stderr, "%s: nlist(%s) failed\n", Progname, Kernel);
X		exit(1);
X	}
X	if ((fd = open("/dev/kmem", O_RDONLY)) < 0) {
X		fprintf(stderr, "%s: open(/dev/kmem) failed [%s]\n",
X			Progname, strerror(errno));
X		exit(1);
X	}
X	if (lseek(fd, (long)nl[0].n_value, 0) == -1) {
X		fprintf(stderr, "%s: lseek(/dev/kmem) failed [%s]\n",
X			Progname, strerror(errno));
X		exit(1);
X	}
X	if (read(fd, (char *)&kb, sizeof(kb)) != sizeof(kb)) {
X		fprintf(stderr, "%s: read(/dev/kmem) failed [%s]\n",
X			Progname, strerror(errno));
X		exit(1);
X	}
X	curr_scrn = kb.kg_curscrn+1;
X	close(fd);
X
X	/*
X	 * We only needed priviliges to get the active screen.  Renounce them.
X	 */
X	setuid(getuid());
X	setgid(getgid());
X
X	/*
X	 * Open up the the selected screen.  Switch display to the selected
X	 * screen.  Get the display mode and map in the display memory.
X	 */
X	if ((fd = open(scrname, O_RDWR)) < 0) {
X		fprintf(stderr, "%s: could not open '%s' [%s]\n",
X			Progname, scrname, strerror(errno));
X		exit(1);
X	}
X	setscreen(fd_cons, sel_scrn);
X	if ((disp_mode = ioctl(fd, CONS_GET, 0)) < 0) {
X		setscreen(fd_cons, curr_scrn);
X		fprintf(stderr, "%s: could not get display type [%s]\n",
X			Progname, strerror(errno));
X		exit(1);
X	}
X	if ((disp_mem = (char *)ioctl(fd, MAPCONS, 0)) == NULL) {
X		setscreen(fd_cons, curr_scrn);
X		fprintf(stderr, "%s: could not map display memory [%s]\n",
X			Progname, strerror(errno));
X		exit(1);
X	}
X	(void) close(fd);
X
X	/*
X	 * Determine the size of the screen in the current mode.
X	 */
X	for (i = 0 ; Disptab[i].mode >= 0 && Disptab[i].mode != disp_mode ; ++i)
X		;
X	if (Disptab[i].mode < 0) {
X		setscreen(fd_cons, curr_scrn);
X		fprintf(stderr, "%s: display not in supported text mode\n", Progname);
X		exit(1);
X	}
X	num_cols = Disptab[i].ncols;
X	num_rows = Disptab[i].nrows;
X
X	/*
X	 * Extract the characters from display memory and send to stdout.
X	 */
X	for (row = 0 ; row < num_rows ; ++row) {
X		for (col = 0 ; col < num_cols ; ++col) {
X			linebuf[col] = *disp_mem;
X			disp_mem += 2;
X		}
X		linebuf[col] = '\0';
X		puts(strtrim(linebuf));
X	}
X
X	/*
X	 * Restore back to the original screen.
X	 */
X	setscreen(fd_cons, curr_scrn);
X
X	exit(0);
X	/*NOTREACHED*/
X}
X
X
Xchar *strtrim(str)
Xchar *str;
X{
X	char *s, *nonwhite;
X
X	for (nonwhite = NULL, s = str ; *s != '\0' ; ++s) {
X		if (!isascii(*s) || !isspace(*s))
X			nonwhite = s;
X	}
X
X	if (nonwhite != NULL)
X		*(nonwhite+1) = '\0';
X
X	return str;
X}
X
END_OF_FILE_prtscrn.c
    size="`wc -c < prtscrn.c`"
    if test 6099 -ne "$size" ; then
	echo "prtscrn.c: extraction error - got $size chars"
    fi
fi
if test -f prtscrn.1 -a "$1" != "-c" ; then
    echo "prtscrn.1: file exists - will not be overwritten"
else
    echo "x - prtscrn.1 (file 3 of 3, 550 chars)"
    sed -e 's/^X//' << 'END_OF_FILE_prtscrn.1' > prtscrn.1
X.\" @(#) prtscrn.1 1.2 91/08/17 18:28:53
X.TH PRTSCRN 1L
X.SH NAME
Xprtscrn - Print contents of a console multiscreen.
X.SH SYNTAX
X.B prtscrn
X.BR \- screen_num
X.SH DESCRIPTION
XThe contents of the specified console multiscreen are sent to the
Xstandard output.  If the user does not have permissions to access the
Xspecified screen, then
X.I prtscrn
Xwill fail with an error.
X.SH BUGS
XNever tested with multiple display adapters.
XOnly supports text mode operation.
X.SH AUTHOR
XChip Rosenthal
X.br
XUnicom Systems Development, Inc.
X.br
X<chip@chinacat.unicom.com>
END_OF_FILE_prtscrn.1
    size="`wc -c < prtscrn.1`"
    if test 550 -ne "$size" ; then
	echo "prtscrn.1: extraction error - got $size chars"
    fi
fi
echo "done - 3 files extracted"
exit 0
-- 
Chip Rosenthal  512-482-8260  |  Lotus 1-2-3 for UNIX...it's a product
Unicom Systems Development    |  you don't have to support.
<chip@chinacat.Unicom.COM>    |    - recent Lotus 1-2-3 advert


exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.
