home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume30 / prtscrn2 / part01 < prev    next >
Encoding:
Text File  |  1992-06-20  |  16.4 KB  |  576 lines

  1. Newsgroups: comp.sources.misc
  2. From: Chip Rosenthal <chip@chinacat.unicom.com>
  3. Subject:  v30i076:  prtscrn2 - screen dump utility for SCO UNIX/XENIX, Part01/01
  4. Message-ID: <1992Jun21.040704.3057@sparky.imd.sterling.com>
  5. X-Md4-Signature: 4a41ccc8c23bd9fc48fcd3d23e924ccb
  6. Date: Sun, 21 Jun 1992 04:07:04 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: Chip Rosenthal <chip@chinacat.unicom.com>
  10. Posting-number: Volume 30, Issue 76
  11. Archive-name: prtscrn2/part01
  12. Environment: SCO
  13. Supersedes: prtscrn: Volume 22, Issue 27
  14.  
  15. If you'll page down a dozen lines you'll hit the README which
  16. pretty well summarizes this utility...
  17.  
  18. #! /bin/sh
  19. # this is a "shar" archive - run through "/bin/sh" to extract 4 files:
  20. #   README prtscrn.c prtscrn.1 Makefile
  21. # Wrapped by chip@chinacat on Wed Jun 17 01:18:36 CDT 1992
  22. # Unpacking this archive requires:  sed test wc (possibly mkdir)
  23. # Existing files will not be clobbered unless "-c" is specified on the cmd line.
  24. if test -f README -a "$1" != "-c" ; then
  25.     echo "README: file exists - will not be overwritten"
  26. else
  27.     echo "x - README (file 1 of 4, 1377 chars)"
  28.     sed -e 's/^X//' << 'END_OF_FILE_README' > README
  29. X@(#) README 1.3 92/06/16 21:17:03
  30. X
  31. X`prtscrn' grabs the contents of a console MultiScreen(tm) on SCO
  32. XUNIX and XENIX systems.
  33. X
  34. XTo dump the contents of /dev/tty01 to a file, you'd run:
  35. X
  36. X    prtscrn -1 >filename
  37. X
  38. XTo dump the contents of the current screen, simply run:
  39. X
  40. X    prtscrn >filename
  41. X
  42. XAn earlier version of the `prtscrn' program was published in
  43. Xcomp.sources.misc volume 22.  This version has many improvements.
  44. X
  45. X    - This release uses console ioctl() calls rather than groping in
  46. X      the kernel or system memory, and thus no longer needs to be
  47. X      installed with privileges.
  48. X
  49. X    - This version is portable between SCO XENIX and SCO UNIX.  Not
  50. X      only are there no longer special ifdef's, but also a binary
  51. X      compiled on one of these will work on the other.
  52. X
  53. X    - The old version was subject to problems where the output was
  54. X      strangely shifted and wrapped about.  This version should be
  55. X      resistent to those bugs.
  56. X
  57. X    - This version will work from non-console terminals.  For example,
  58. X      if you are on a serial terminal you can grab the contents of
  59. X      a console multiscreen -- permissions willing.  (Pretty nifty
  60. X      stuff all you software documentation writers out there -- huh?)
  61. X
  62. X    - I've coded this version to hopefully support systems with multiple
  63. X      display adapters, but I haven't tested it.
  64. X
  65. XChip Rosenthal
  66. X<chip@chinacat.Unicom.COM>
  67. END_OF_FILE_README
  68.     size="`wc -c < README`"
  69.     if test 1377 -ne "$size" ; then
  70.     echo "README: extraction error - got $size chars"
  71.     fi
  72. fi
  73. if test -f prtscrn.c -a "$1" != "-c" ; then
  74.     echo "prtscrn.c: file exists - will not be overwritten"
  75. else
  76.     echo "x - prtscrn.c (file 2 of 4, 11261 chars)"
  77.     sed -e 's/^X//' << 'END_OF_FILE_prtscrn.c' > prtscrn.c
  78. X#ifndef lint
  79. Xstatic char SCCSID[] = "@(#) prtscrn.c 1.6 92/06/17 01:09:54";
  80. X#endif
  81. X
  82. X/*
  83. X * prtscrn - SCO UNIX/XENIX console screen dump utility.
  84. X *
  85. X * This works by attaching to the display adapter memory and extracting
  86. X * the out the characters and dumping them to stdout.  In order to
  87. X * do this we need to make the selected screen active so that it's
  88. X * contents are loaded into display memory.  What gets tricky is that
  89. X * we need to figure out what screen is on the adapter when we begin
  90. X * so we can put that screen back when we are done.
  91. X *
  92. X * One way to find out what screen is active is to open up the
  93. X * display adapter (e.g. "/dev/vga") and do a CONS_GETINFO ioctl()
  94. X * upon it.  However, we first need to know what kind of display
  95. X * adapter is being used.  If we are dumping a specific screen
  96. X * (i.e. a screen number was given on the command line) then we
  97. X * will open up that tty, and do a CONS_CURRENT ioctl() upon it
  98. X * to get the adapter type.  If we are dumping the current screen
  99. X * (i.e.  no screen number given on the command line) then we
  100. X * will do the CONS_CURRENT ioctl() upon "/dev/tty".  Note that
  101. X * a side effect of this is that we should be able to make a dump
  102. X * of a screen from any terminal on the system (permissions
  103. X * willing), and further this should work on a system with multiple
  104. X * display adapters.
  105. X *
  106. X * Security is enforced by permissions on the console tty.  That is,
  107. X * if you try to dump screen 2, then you need to have read/write
  108. X * permissions to /dev/tty02.  This utility assumes that the user
  109. X * has read permissions on the adapter device, e.g. /dev/vga.  The
  110. X * default is to grant world read/write for these devices.  I'm not
  111. X * sure that is wise, but we assume that's the way things are.
  112. X *
  113. X * Edit at tabstops=4.
  114. X *
  115. X * Chip Rosenthal
  116. X * Unicom Systems Development, Inc.
  117. X * <chip@chinacat.unicom.com>
  118. X */
  119. X
  120. X#include <stdio.h>
  121. X#include <ctype.h>
  122. X#include <string.h>
  123. X#include <fcntl.h>
  124. X#include <errno.h>
  125. X#include <varargs.h>
  126. X#include <sys/types.h>
  127. X#include <sys/ioctl.h>
  128. X#include <sys/vid.h>
  129. X#include <sys/console.h>
  130. X#include <sys/vtkd.h>
  131. X
  132. X#define USAGE    "usage: %s [-screen_num]\n"
  133. X
  134. Xchar *Progname;
  135. X
  136. X/*
  137. X * Error message handling is a bit tricky because we are changing
  138. X * around the screen display, and we need to ensure the proper screen
  139. X * is active before displaying messages.  Therefore, we will not
  140. X * print error messages, but rather call the "set_error()" routine
  141. X * to save off the message to "Errbuf[]".  In the event of an error,
  142. X * we can restore the screen display and then print the contents of
  143. X * "Errbuf[]".
  144. X */
  145. Xchar Errbuf[512];
  146. X
  147. X/*
  148. X * This is the list of valid text (i.e. non-graphics) display modes.
  149. X * We will ensure that the display mode of the selected screen is in
  150. X * this list prior to performing the dump.
  151. X */
  152. Xint Text_modes[] = {
  153. X    M_B40x25, M_C40x25, M_B80x25, M_C80x25, M_EGAMONO80x25, M_ENH_B40x25,
  154. X    M_ENH_C40x25, M_ENH_B80x25, M_ENH_C80x25, M_VGA_40x25, M_VGA_80x25,
  155. X    M_VGA_M80x25, M_ENH_B80x43, M_ENH_C80x43, M_MCA_MODE, -1
  156. X};
  157. X
  158. Xint open_adapter(int);
  159. Xchar *activate_screen(int, int);
  160. Xint deactivate_screen(int, int);
  161. Xint dump_screen(int, FILE *, char *);
  162. Xvoid set_error(int, char *,);
  163. X
  164. X
  165. Xmain(argc, argv)
  166. Xint argc;
  167. Xchar *argv[];
  168. X{
  169. X    struct vid_info vinfo;
  170. X    char *disp_mem;
  171. X    int orig_scrn_num, sel_scrn_num, fd, i;
  172. X
  173. X    Progname = argv[0];
  174. X
  175. X    /*
  176. X     * Figure out what screen we want to dump.
  177. X     */
  178. X    switch (argc) {
  179. X    case 1:
  180. X        sel_scrn_num = -1;
  181. X        break;
  182. X    case 2:
  183. X        if (argv[1][0] != '-') {
  184. X            fprintf(stderr, USAGE, Progname);
  185. X            exit(1);
  186. X        }
  187. X        if ((sel_scrn_num = atoi(argv[1]+1)-1) < 0 || sel_scrn_num >= MAXSCRN) {
  188. X            fprintf(stderr, "%s: bad screen number \"%s\" specified\n",
  189. X                Progname, argv[1]+1);
  190. X            exit(1);
  191. X        }
  192. X        break;
  193. X    default:
  194. X        fprintf(stderr, USAGE, Progname);
  195. X        exit(1);
  196. X        /*NOTREACHED*/
  197. X    }
  198. X
  199. X    /*
  200. X     * Open up the display adapter which contains the selected screen.
  201. X     */
  202. X    if ((fd = open_adapter(sel_scrn_num)) < 0) {
  203. X        fputs(Errbuf, stderr);
  204. X        exit(1);
  205. X    }
  206. X
  207. X    /*
  208. X     * Determine what screen is currently active on the display adapter.
  209. X     */
  210. X    vinfo.size = sizeof(vinfo);
  211. X    if (ioctl(fd, CONS_GETINFO, (char *)&vinfo) != sizeof(vinfo)) {
  212. X        set_error(errno, "cannot get display info from active screen");
  213. X        fputs(Errbuf, stderr);
  214. X        exit(1);
  215. X    }
  216. X    orig_scrn_num = vinfo.m_num;
  217. X
  218. X    /*
  219. X     * If we are dumping the current screen then we now know what
  220. X     * the selected screen number is -- the current screen number.
  221. X     */
  222. X    if (sel_scrn_num < 0)
  223. X        sel_scrn_num = orig_scrn_num;
  224. X
  225. X    /*
  226. X     * Kludge alert!  For some reason if we are dumping the current screen
  227. X     * the stuff is sometimes shifted about in display memory.  However,
  228. X     * forcing a quick screen switch seems to cure this problem.
  229. X     */
  230. X    if (sel_scrn_num == orig_scrn_num) {
  231. X        if ((i = sel_scrn_num + 1) >= MAXSCRN)
  232. X            i = 0;
  233. X        (void) ioctl(fd, VT_ACTIVATE, i);
  234. X    }
  235. X
  236. X    /*
  237. X     * Bring the selected screen up on the display adapter and get a
  238. X     * pointer to the video display memory.
  239. X     *
  240. X     * From here on out we need to make sure we call deactivate_screen()
  241. X     * to return the original screen to the display.
  242. X     */
  243. X    if ((disp_mem = activate_screen(fd, sel_scrn_num)) == NULL) {
  244. X        (void) deactivate_screen(fd, orig_scrn_num);
  245. X        fputs(Errbuf, stderr);
  246. X        exit(1);
  247. X    }
  248. X
  249. X    /*
  250. X     * Dump the selected screen to stdout.
  251. X     */
  252. X    if (dump_screen(fd, stdout, disp_mem) != 0) {
  253. X        (void) deactivate_screen(fd, orig_scrn_num);
  254. X        fputs(Errbuf, stderr);
  255. X        exit(1);
  256. X    }
  257. X
  258. X    /*
  259. X     * Done.
  260. X     */
  261. X    (void) deactivate_screen(fd, orig_scrn_num);
  262. X    exit(0);
  263. X    /*NOTREACHED*/
  264. X}
  265. X
  266. X
  267. X/*
  268. X * Open up the display adapter containing screen number "scrn".  Returns
  269. X * a file descriptor to the display adapter, or -1 upon error.  If an
  270. X * error occurs, a diagnostic will be stored in "Errbuf[]".
  271. X */
  272. Xint open_adapter(scrn)
  273. Xint scrn;            /* screen number - from zero through MAXSCRN-1.        */
  274. X{
  275. X    char *disp_dev, scrn_dev[256];
  276. X    int fd, i;
  277. X
  278. X    /*
  279. X     * Open up the selected screen.
  280. X     */
  281. X    sprintf(scrn_dev, (scrn < 0 ? "/dev/tty" : "/dev/tty%02d"), scrn+1);
  282. X    if ((fd = open(scrn_dev, O_RDWR)) < 0) {
  283. X        set_error(errno, "cannot open screen \"%s\"", scrn_dev);
  284. X        return -1;
  285. X    }
  286. X
  287. X    /*
  288. X     * Determine what sort of display adapter is used for this screen.
  289. X     */
  290. X    if ((i = ioctl(fd, CONS_CURRENT, (char *)0)) < 0) {
  291. X        set_error(errno, "cannot get display type of \"%s\"", scrn_dev);
  292. X        return -1;
  293. X    }
  294. X    switch (i) {
  295. X    case MONO:
  296. X        disp_dev = "/dev/mono";
  297. X        break;
  298. X    case CGA:
  299. X        disp_dev = "/dev/cga";
  300. X        break;
  301. X    case EGA:
  302. X        disp_dev = "/dev/ega";
  303. X        break;
  304. X    case VGA:
  305. X        disp_dev = "/dev/vga";
  306. X        break;
  307. X    default:
  308. X        set_error(0, "unknown display type 0x%X on \"%s\"", i, scrn_dev);
  309. X        return -1;
  310. X    }
  311. X
  312. X    /*
  313. X     * Close up the screen and open up the display adapter instead.
  314. X     */
  315. X    (void) close(fd);
  316. X    if ((fd = open(disp_dev, O_RDONLY)) < 0) {
  317. X        set_error(errno, "cannot open display adapter \"%s\"", disp_dev);
  318. X        return -1;
  319. X    }
  320. X
  321. X    return fd;
  322. X}
  323. X
  324. X
  325. X/*
  326. X * Bring the selected screen up on the display adapter and map video memory.
  327. X * Returns a pointer to the video display memory segment, or NULL upon error.
  328. X * If an error occurs, a diagnostic will be stored in "Errbuf[]".
  329. X */
  330. Xchar *activate_screen(fd, scr_num)
  331. Xint fd;                /* file descriptor to the display adapter                */
  332. Xint scr_num;        /* screen to activate, zero through MAXSCRN-1            */
  333. X{
  334. X    char *disp_mem;
  335. X    int disp_mode, i;
  336. X
  337. X    /*
  338. X     * Kludge alert!  There seems to be some sort of race in the kernel
  339. X     * if we switch to a screen in graphics mode and immediately back
  340. X     * to one in text mode.
  341. X     */
  342. X    (void) nap(100L);
  343. X
  344. X    /*
  345. X     * Activate the selected screen.
  346. X     */
  347. X    if (ioctl(fd, VT_ACTIVATE, scr_num) != 0) {
  348. X        set_error(0, "cannot switch to screen %d", scr_num+1);
  349. X        return (char *) NULL;
  350. X    }
  351. X
  352. X    /*
  353. X     * Verify that the selected screen is in a text mode.
  354. X     */
  355. X    if ((disp_mode = ioctl(fd, CONS_GET, (char *)0)) < 0) {
  356. X        set_error(errno, "cannot get display mode from selected screen");
  357. X        return (char *) NULL;
  358. X    }
  359. X    for (i = 0 ; Text_modes[i] != disp_mode ; ++i) {
  360. X        if (Text_modes[i] < 0) {
  361. X            set_error(0, "selected screen not in text mode");
  362. X            return (char *) NULL;
  363. X        }
  364. X    }
  365. X
  366. X    /*
  367. X     * Get a pointer to the video adapter display memory.
  368. X     */
  369. X    if ((disp_mem = (char *)ioctl(fd, MAPCONS, 0)) == NULL) {
  370. X        set_error(errno, "cannot map selected screen display memory");
  371. X        return (char *) NULL;
  372. X    }
  373. X
  374. X    return disp_mem;
  375. X}
  376. X
  377. X
  378. X/*
  379. X * Restore a the original screen to the display and close out the file
  380. X * descriptor to the display adapter.  Returns zero upon success, or -1
  381. X * upon error.  If an error occurs, a diagnostic will be stored in "Errbuf[]".
  382. X */
  383. Xint deactivate_screen(fd, scr_num)
  384. Xint fd;                /* file descriptor to the display adapter                */
  385. Xint scr_num;        /* screen to restore, zero through MAXSCRN-1            */
  386. X{
  387. X
  388. X    /*
  389. X     * Kludge alert!  There seems to be some sort of race in the kernel
  390. X     * if we switch to a screen in graphics mode and immediately back
  391. X     * to one in text mode.
  392. X     */
  393. X    (void) nap(100L);
  394. X
  395. X    if (ioctl(fd, VT_ACTIVATE, scr_num) != 0) {
  396. X        set_error(errno, "cannot switch to screen %d", scr_num+1);
  397. X        return -1;
  398. X    }
  399. X    (void) close(fd);
  400. X    return 0;
  401. X}
  402. X
  403. X
  404. X/*
  405. X * Dump the contents of the active screen.  Returns zero upon success,
  406. X * or -1 upon error.  If an error occurs, a diagnostic will be stored
  407. X * in "Errbuf[]".
  408. X */
  409. Xint dump_screen(disp_fd, out_fp, disp_mem)
  410. Xint disp_fd;        /* file descriptor to the display adapter                */
  411. XFILE *out_fp;        /* stream to send display dump to                        */
  412. Xchar *disp_mem;        /* pointer to video display memory                        */
  413. X{
  414. X    struct vid_info vinfo;
  415. X    char *buf, *bp;
  416. X    int num_rows, num_cols, row, col;
  417. X    extern char *malloc();
  418. X    extern void free();
  419. X
  420. X    /*
  421. X     * Get the row/column size of the selected screen.
  422. X     */
  423. X    vinfo.size = sizeof(vinfo);
  424. X    if (ioctl(disp_fd, CONS_GETINFO, (char *)&vinfo) != sizeof(vinfo)) {
  425. X        set_error(errno, "cannot get display info from selected screen");
  426. X        return -1;
  427. X    }
  428. X    num_rows = vinfo.mv_rsz;
  429. X    num_cols = vinfo.mv_csz;
  430. X
  431. X    /*
  432. X     * Allocate space to hold a line of the display.
  433. X     */
  434. X    if ((buf = malloc((unsigned)num_cols+1)) == NULL) {
  435. X        set_error(0, "out of memory [malloc failed]");
  436. X        return -1;
  437. X    }
  438. X
  439. X    /*
  440. X     * Extract the characters from display memory and send to stdout.
  441. X     * Trailing spaces will be trimmed from the line.
  442. X     */
  443. X    for (row = 0 ; row < num_rows ; ++row) {
  444. X
  445. X        /*
  446. X         * Extract the next line of text from the display.  Each character
  447. X         * cell uses two bytes:  one containing the actual character and
  448. X         * one containing the display attributes.  We need to skip over
  449. X         * the display attributes as we run through the memory.
  450. X         */
  451. X        for (col = 0, bp = buf ; col < num_cols ; ++col, ++bp) {
  452. X            *bp = *disp_mem;
  453. X            disp_mem += 2;
  454. X        }
  455. X
  456. X        /*
  457. X         * Trim trailing space from line.  This loop is not portable
  458. X         * since "bp" < "buf" is not guaranteed to be legal, but it
  459. X         * works on SCO UNIX 3.2 and XENIX 2.3.
  460. X         */
  461. X        while (--bp >= buf && *bp == ' ')
  462. X            ;
  463. X        *++bp = '\0';
  464. X
  465. X        /*
  466. X         * Output the line.
  467. X         */
  468. X        fputs(buf, out_fp);
  469. X        putc('\n', out_fp);
  470. X    }
  471. X
  472. X    (void) free(buf);
  473. X    return 0;
  474. X}
  475. X
  476. X
  477. X/*
  478. X * Save a diagnostic message to "Errbuf[]".
  479. X */
  480. X/*VARARGS2*/
  481. Xvoid set_error(err, fmt, va_alist)
  482. Xint err;
  483. Xchar *fmt;
  484. Xva_dcl
  485. X{
  486. X    va_list args;
  487. X    char *s;
  488. X    extern char *sys_errlist[];
  489. X
  490. X    va_start(args);
  491. X    (void) strcpy(Errbuf, Progname);
  492. X    s = Errbuf + strlen(Errbuf);
  493. X    *s++ = ':';
  494. X    *s++ = ' ';
  495. X    (void) vsprintf(s, fmt, args);
  496. X    s += strlen(s);
  497. X    if (err > 0) {
  498. X        (void) sprintf(s, " [%s]", sys_errlist[err]);
  499. X        s += strlen(s);
  500. X    }
  501. X    *s++ = '\n';
  502. X    *s = '\0';
  503. X    va_end(args);
  504. X}
  505. X
  506. END_OF_FILE_prtscrn.c
  507.     size="`wc -c < prtscrn.c`"
  508.     if test 11261 -ne "$size" ; then
  509.     echo "prtscrn.c: extraction error - got $size chars"
  510.     fi
  511. fi
  512. if test -f prtscrn.1 -a "$1" != "-c" ; then
  513.     echo "prtscrn.1: file exists - will not be overwritten"
  514. else
  515.     echo "x - prtscrn.1 (file 3 of 4, 836 chars)"
  516.     sed -e 's/^X//' << 'END_OF_FILE_prtscrn.1' > prtscrn.1
  517. X.\" @(#) prtscrn.1 1.5 92/06/16 21:17:04
  518. X.TH PRTSCRN 1L
  519. X.SH NAME
  520. Xprtscrn \- Print contents of a console multiscreen.
  521. X.SH SYNTAX
  522. X.B prtscrn
  523. X[ \-screen_num ]
  524. X.SH DESCRIPTION
  525. XThe contents of the specified console multiscreen are sent to the
  526. Xstandard output.  If no
  527. X.I screen_num
  528. Xis specified then the current screen is dumped.  If the user does not
  529. Xhave permissions to access the specified screen, then
  530. X.I prtscrn
  531. Xwill fail with an error.  The
  532. X.I prtscrn
  533. Xutility need not be run from the console.  For example, you can dump
  534. Xa console screen from a serial terminal, permissions willing.
  535. X.SH BUGS
  536. XNever tested with multiple display adapters.
  537. XOnly supports text mode operation.
  538. XAlthough it will handle eight-bit characters, it won't do attributes.
  539. X.SH AUTHOR
  540. XChip Rosenthal
  541. X.br
  542. XUnicom Systems Development, Inc.
  543. X.br
  544. X<chip@chinacat.unicom.com>
  545. END_OF_FILE_prtscrn.1
  546.     size="`wc -c < prtscrn.1`"
  547.     if test 836 -ne "$size" ; then
  548.     echo "prtscrn.1: extraction error - got $size chars"
  549.     fi
  550. fi
  551. if test -f Makefile -a "$1" != "-c" ; then
  552.     echo "Makefile: file exists - will not be overwritten"
  553. else
  554.     echo "x - Makefile (file 4 of 4, 76 chars)"
  555.     sed -e 's/^X//' << 'END_OF_FILE_Makefile' > Makefile
  556. XSHELL = /bin/sh
  557. X
  558. Xprtscrn : prtscrn.o
  559. X    $(CC) $(LDFLAGS) -o $@ prtscrn.o -lx
  560. X
  561. END_OF_FILE_Makefile
  562.     size="`wc -c < Makefile`"
  563.     if test 76 -ne "$size" ; then
  564.     echo "Makefile: extraction error - got $size chars"
  565.     fi
  566. fi
  567. echo "done - 4 files extracted"
  568. exit 0
  569. -- 
  570. Chip Rosenthal  512-482-8260 | Let the wayward children play.  Let the wicked
  571. Unicom Systems Development   | have their day.  Let the chips fall where they
  572. <chip@chinacat.Unicom.COM>   | may.  I'm going to Disneyland.  -Timbuk 3
  573.  
  574.  
  575. exit 0 # Just in case...
  576.