10Sstevel@tonic-gate /*
2*549Smuffin * Copyright 2001 Sun Microsystems, Inc. All rights reserved.
3*549Smuffin * Use is subject to license terms.
40Sstevel@tonic-gate */
50Sstevel@tonic-gate
60Sstevel@tonic-gate /*
70Sstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California.
80Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement
90Sstevel@tonic-gate * specifies the terms and conditions for redistribution.
100Sstevel@tonic-gate */
11*549Smuffin
120Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
130Sstevel@tonic-gate
140Sstevel@tonic-gate /*
150Sstevel@tonic-gate * remcap - routines for dealing with the remote host data base
160Sstevel@tonic-gate *
170Sstevel@tonic-gate * derived from termcap
180Sstevel@tonic-gate */
190Sstevel@tonic-gate #ifdef USG
200Sstevel@tonic-gate #include <sys/types.h>
210Sstevel@tonic-gate #include <fcntl.h> /* for O_RDONLY */
220Sstevel@tonic-gate #else
230Sstevel@tonic-gate #include <sys/file.h> /* for O_RDONLY */
240Sstevel@tonic-gate #include <ctype.h>
250Sstevel@tonic-gate #endif
260Sstevel@tonic-gate
27*549Smuffin #include <stdlib.h>
28*549Smuffin #include <string.h>
29*549Smuffin #include <unistd.h>
30*549Smuffin #include <ctype.h>
31*549Smuffin
320Sstevel@tonic-gate #ifndef BUFSIZ
330Sstevel@tonic-gate #define BUFSIZ 1024
340Sstevel@tonic-gate #endif
350Sstevel@tonic-gate #define MAXHOP 32 /* max number of tc= indirections */
360Sstevel@tonic-gate #define SYSREMOTE "/etc/remote" /* system remote file */
370Sstevel@tonic-gate
380Sstevel@tonic-gate #define tgetent rgetent
390Sstevel@tonic-gate #define tnchktc rnchktc
400Sstevel@tonic-gate #define tnamatch rnamatch
410Sstevel@tonic-gate #define tgetnum rgetnum
420Sstevel@tonic-gate #define tgetflag rgetflag
430Sstevel@tonic-gate #define tgetstr rgetstr
440Sstevel@tonic-gate #define E_TERMCAP RM = SYSREMOTE
450Sstevel@tonic-gate #define V_TERMCAP "REMOTE"
460Sstevel@tonic-gate #define V_TERM "HOST"
470Sstevel@tonic-gate
480Sstevel@tonic-gate char *RM;
490Sstevel@tonic-gate
500Sstevel@tonic-gate /*
510Sstevel@tonic-gate * termcap - routines for dealing with the terminal capability data base
520Sstevel@tonic-gate *
530Sstevel@tonic-gate * BUG: Should use a "last" pointer in tbuf, so that searching
540Sstevel@tonic-gate * for capabilities alphabetically would not be a n**2/2
550Sstevel@tonic-gate * process when large numbers of capabilities are given.
560Sstevel@tonic-gate * Note: If we add a last pointer now we will screw up the
570Sstevel@tonic-gate * tc capability. We really should compile termcap.
580Sstevel@tonic-gate *
590Sstevel@tonic-gate * Essentially all the work here is scanning and decoding escapes
600Sstevel@tonic-gate * in string capabilities. We don't use stdio because the editor
610Sstevel@tonic-gate * doesn't, and because living w/o it is not hard.
620Sstevel@tonic-gate */
630Sstevel@tonic-gate
64*549Smuffin static char *tbuf;
65*549Smuffin static int hopcount; /* detect infinite loops in termcap, init 0 */
66*549Smuffin static char *remotefile;
67*549Smuffin
68*549Smuffin static char *tskip(char *);
69*549Smuffin static char *tdecode(char *, char **);
70*549Smuffin
71*549Smuffin char *tgetstr(char *, char **);
72*549Smuffin int getent(char *, char *, char *, int);
73*549Smuffin int tnchktc(void);
74*549Smuffin int tnamatch(char *);
75*549Smuffin
76*549Smuffin extern void myperm(void);
77*549Smuffin extern void userperm(void);
780Sstevel@tonic-gate
790Sstevel@tonic-gate /*
800Sstevel@tonic-gate * If we use a user specified entry to get the device name,
810Sstevel@tonic-gate * we need to open the device as the user.
820Sstevel@tonic-gate */
830Sstevel@tonic-gate int trusted_device = 0;
840Sstevel@tonic-gate
850Sstevel@tonic-gate /*
860Sstevel@tonic-gate * Get an entry for terminal name in buffer bp,
870Sstevel@tonic-gate * from the termcap file. Parse is very rudimentary;
880Sstevel@tonic-gate * we just notice escaped newlines.
890Sstevel@tonic-gate */
90*549Smuffin int
tgetent(char * bp,char * name,int len)91*549Smuffin tgetent(char *bp, char *name, int len)
920Sstevel@tonic-gate {
930Sstevel@tonic-gate char lbuf[BUFSIZ], *cp, *p;
940Sstevel@tonic-gate int rc1, rc2;
950Sstevel@tonic-gate
960Sstevel@tonic-gate trusted_device = 1;
970Sstevel@tonic-gate
980Sstevel@tonic-gate remotefile = cp = getenv(V_TERMCAP);
990Sstevel@tonic-gate if (cp == (char *)0 || strcmp(cp, SYSREMOTE) == 0) {
1000Sstevel@tonic-gate remotefile = cp = SYSREMOTE;
1010Sstevel@tonic-gate return (getent(bp, name, cp, len));
1020Sstevel@tonic-gate } else {
1030Sstevel@tonic-gate if ((rc1 = getent(bp, name, cp, len)) != 1)
1040Sstevel@tonic-gate *bp = '\0';
1050Sstevel@tonic-gate remotefile = cp = SYSREMOTE;
1060Sstevel@tonic-gate rc2 = getent(lbuf, name, cp, sizeof (lbuf));
1070Sstevel@tonic-gate if (rc1 != 1 && rc2 != 1)
1080Sstevel@tonic-gate return (rc2);
1090Sstevel@tonic-gate if (rc2 == 1) {
1100Sstevel@tonic-gate p = lbuf;
1110Sstevel@tonic-gate if (rc1 == 1)
1120Sstevel@tonic-gate while (*p++ != ':')
1130Sstevel@tonic-gate ;
1140Sstevel@tonic-gate if (strlen(bp) + strlen(p) >= len) {
115*549Smuffin (void) write(2, "Remcap entry too long\n", 23);
1160Sstevel@tonic-gate return (-1);
1170Sstevel@tonic-gate }
118*549Smuffin (void) strcat(bp, p);
1190Sstevel@tonic-gate }
1200Sstevel@tonic-gate tbuf = bp;
1210Sstevel@tonic-gate return (1);
1220Sstevel@tonic-gate }
1230Sstevel@tonic-gate }
1240Sstevel@tonic-gate
125*549Smuffin int
getent(char * bp,char * name,char * cp,int len)126*549Smuffin getent(char *bp, char *name, char *cp, int len)
1270Sstevel@tonic-gate {
128*549Smuffin int c;
129*549Smuffin int i = 0, cnt = 0;
1300Sstevel@tonic-gate char ibuf[BUFSIZ], *cp2;
1310Sstevel@tonic-gate int tf;
1320Sstevel@tonic-gate int safe = 1; /* reset only when we open the user's $REMOTE */
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate tbuf = bp;
1350Sstevel@tonic-gate tf = 0;
1360Sstevel@tonic-gate /*
1370Sstevel@tonic-gate * TERMCAP can have one of two things in it. It can be the
1380Sstevel@tonic-gate * name of a file to use instead of /etc/termcap. In this
1390Sstevel@tonic-gate * case it better start with a "/". Or it can be an entry to
1400Sstevel@tonic-gate * use so we don't have to read the file. In this case it
1410Sstevel@tonic-gate * has to already have the newlines crunched out.
1420Sstevel@tonic-gate */
1430Sstevel@tonic-gate if (cp && *cp) {
1440Sstevel@tonic-gate if (*cp != '/') {
1450Sstevel@tonic-gate cp2 = getenv(V_TERM);
1460Sstevel@tonic-gate if (cp2 == (char *)0 || strcmp(name, cp2) == 0) {
1470Sstevel@tonic-gate if (strstr(cp, "dv=") != 0)
1480Sstevel@tonic-gate trusted_device = 0;
149*549Smuffin (void) strncpy(bp, cp, len-1);
1500Sstevel@tonic-gate bp[len-1] = '\0';
1510Sstevel@tonic-gate return (tnchktc());
1520Sstevel@tonic-gate } else
1530Sstevel@tonic-gate tf = open(E_TERMCAP, O_RDONLY);
1540Sstevel@tonic-gate } else {
1550Sstevel@tonic-gate /* open SYSREMOTE as uucp, other files as user */
1560Sstevel@tonic-gate safe = strcmp(cp, SYSREMOTE) == 0;
1570Sstevel@tonic-gate if (!safe)
1580Sstevel@tonic-gate userperm();
1590Sstevel@tonic-gate tf = open(RM = cp, O_RDONLY);
1600Sstevel@tonic-gate if (!safe)
1610Sstevel@tonic-gate myperm();
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate if (tf == 0)
1650Sstevel@tonic-gate tf = open(E_TERMCAP, O_RDONLY);
1660Sstevel@tonic-gate if (tf < 0)
1670Sstevel@tonic-gate return (-1);
1680Sstevel@tonic-gate for (;;) {
1690Sstevel@tonic-gate cp = bp;
1700Sstevel@tonic-gate for (;;) {
1710Sstevel@tonic-gate if (i == cnt) {
1720Sstevel@tonic-gate cnt = read(tf, ibuf, BUFSIZ);
1730Sstevel@tonic-gate if (cnt <= 0) {
174*549Smuffin (void) close(tf);
1750Sstevel@tonic-gate return (0);
1760Sstevel@tonic-gate }
1770Sstevel@tonic-gate i = 0;
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate c = ibuf[i++];
1800Sstevel@tonic-gate if (c == '\n') {
1810Sstevel@tonic-gate if (cp > bp && cp[-1] == '\\') {
1820Sstevel@tonic-gate cp--;
1830Sstevel@tonic-gate continue;
1840Sstevel@tonic-gate }
1850Sstevel@tonic-gate break;
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate if (cp >= bp+len) {
188*549Smuffin (void) write(2, "Remcap entry too long\n", 23);
1890Sstevel@tonic-gate break;
1900Sstevel@tonic-gate } else
1910Sstevel@tonic-gate *cp++ = c;
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate *cp = 0;
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate /*
1960Sstevel@tonic-gate * The real work for the match.
1970Sstevel@tonic-gate */
1980Sstevel@tonic-gate if (tnamatch(name)) {
1990Sstevel@tonic-gate /*
2000Sstevel@tonic-gate * if a dv= entry is obtained from $REMOTE,
2010Sstevel@tonic-gate * switch off trusted_device status
2020Sstevel@tonic-gate */
2030Sstevel@tonic-gate if (!safe && strstr(bp, "dv=") != 0)
2040Sstevel@tonic-gate trusted_device = 0;
205*549Smuffin (void) close(tf);
2060Sstevel@tonic-gate return (tnchktc());
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate }
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate /*
2120Sstevel@tonic-gate * tnchktc: check the last entry, see if it's tc=xxx. If so,
2130Sstevel@tonic-gate * recursively find xxx and append that entry (minus the names)
2140Sstevel@tonic-gate * to take the place of the tc=xxx entry. This allows termcap
2150Sstevel@tonic-gate * entries to say "like an HP2621 but doesn't turn on the labels".
2160Sstevel@tonic-gate * Note that this works because of the left to right scan.
2170Sstevel@tonic-gate */
218*549Smuffin int
tnchktc(void)219*549Smuffin tnchktc(void)
2200Sstevel@tonic-gate {
221*549Smuffin char *p, *q;
2220Sstevel@tonic-gate char tcname[64]; /* name of similar terminal */
2230Sstevel@tonic-gate char tcbuf[BUFSIZ];
2240Sstevel@tonic-gate char *holdtbuf = tbuf;
2250Sstevel@tonic-gate int l;
2260Sstevel@tonic-gate
2270Sstevel@tonic-gate p = tbuf + strlen(tbuf) - 2; /* before the last colon */
2280Sstevel@tonic-gate while (*--p != ':')
2290Sstevel@tonic-gate if (p < tbuf) {
230*549Smuffin (void) write(2, "Bad remcap entry\n", 18);
2310Sstevel@tonic-gate return (0);
2320Sstevel@tonic-gate }
2330Sstevel@tonic-gate p++;
2340Sstevel@tonic-gate /* p now points to beginning of last field */
2350Sstevel@tonic-gate if (p[0] != 't' || p[1] != 'c')
2360Sstevel@tonic-gate return (1);
237*549Smuffin (void) strlcpy(tcname, p+3, sizeof (tcname));
2380Sstevel@tonic-gate q = tcname;
2390Sstevel@tonic-gate while (*q && *q != ':')
2400Sstevel@tonic-gate q++;
2410Sstevel@tonic-gate *q = 0;
2420Sstevel@tonic-gate if (++hopcount > MAXHOP) {
243*549Smuffin (void) write(2, "Infinite tc= loop\n", 18);
2440Sstevel@tonic-gate return (0);
2450Sstevel@tonic-gate }
2460Sstevel@tonic-gate if (getent(tcbuf, tcname, remotefile, sizeof (tcbuf)) != 1) {
2470Sstevel@tonic-gate if (strcmp(remotefile, SYSREMOTE) == 0)
2480Sstevel@tonic-gate return (0);
2490Sstevel@tonic-gate else if (getent(tcbuf, tcname, SYSREMOTE, sizeof (tcbuf)) != 1)
2500Sstevel@tonic-gate return (0);
2510Sstevel@tonic-gate }
2520Sstevel@tonic-gate for (q = tcbuf; *q++ != ':'; )
2530Sstevel@tonic-gate ;
2540Sstevel@tonic-gate l = p - holdtbuf + strlen(q);
2550Sstevel@tonic-gate if (l > BUFSIZ) {
256*549Smuffin (void) write(2, "Remcap entry too long\n", 23);
2570Sstevel@tonic-gate q[BUFSIZ - (p-holdtbuf)] = 0;
2580Sstevel@tonic-gate }
259*549Smuffin (void) strcpy(p, q);
2600Sstevel@tonic-gate tbuf = holdtbuf;
2610Sstevel@tonic-gate return (1);
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate /*
2650Sstevel@tonic-gate * Tnamatch deals with name matching. The first field of the termcap
2660Sstevel@tonic-gate * entry is a sequence of names separated by |'s, so we compare
2670Sstevel@tonic-gate * against each such name. The normal : terminator after the last
2680Sstevel@tonic-gate * name (before the first field) stops us.
2690Sstevel@tonic-gate */
270*549Smuffin int
tnamatch(char * np)271*549Smuffin tnamatch(char *np)
2720Sstevel@tonic-gate {
273*549Smuffin char *Np, *Bp;
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate Bp = tbuf;
2760Sstevel@tonic-gate if (*Bp == '#')
2770Sstevel@tonic-gate return (0);
2780Sstevel@tonic-gate for (;;) {
2790Sstevel@tonic-gate for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
2800Sstevel@tonic-gate continue;
2810Sstevel@tonic-gate if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
2820Sstevel@tonic-gate return (1);
2830Sstevel@tonic-gate while (*Bp && *Bp != ':' && *Bp != '|')
2840Sstevel@tonic-gate Bp++;
2850Sstevel@tonic-gate if (*Bp == 0 || *Bp == ':')
2860Sstevel@tonic-gate return (0);
2870Sstevel@tonic-gate Bp++;
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate }
2900Sstevel@tonic-gate
2910Sstevel@tonic-gate /*
2920Sstevel@tonic-gate * Skip to the next field. Notice that this is very dumb, not
2930Sstevel@tonic-gate * knowing about \: escapes or any such. If necessary, :'s can be put
2940Sstevel@tonic-gate * into the termcap file in octal.
2950Sstevel@tonic-gate */
2960Sstevel@tonic-gate static char *
tskip(char * bp)297*549Smuffin tskip(char *bp)
2980Sstevel@tonic-gate {
2990Sstevel@tonic-gate
3000Sstevel@tonic-gate while (*bp && *bp != ':')
3010Sstevel@tonic-gate bp++;
3020Sstevel@tonic-gate if (*bp == ':') {
3030Sstevel@tonic-gate do {
3040Sstevel@tonic-gate bp++;
3050Sstevel@tonic-gate while (isspace(*bp))
3060Sstevel@tonic-gate bp++;
3070Sstevel@tonic-gate } while (*bp == ':');
3080Sstevel@tonic-gate }
3090Sstevel@tonic-gate return (bp);
3100Sstevel@tonic-gate }
3110Sstevel@tonic-gate
3120Sstevel@tonic-gate /*
3130Sstevel@tonic-gate * Return the (numeric) option id.
3140Sstevel@tonic-gate * Numeric options look like
3150Sstevel@tonic-gate * li#80
3160Sstevel@tonic-gate * i.e. the option string is separated from the numeric value by
3170Sstevel@tonic-gate * a # character. If the option is not found we return -1.
3180Sstevel@tonic-gate * Note that we handle octal numbers beginning with 0.
3190Sstevel@tonic-gate */
320*549Smuffin int
tgetnum(char * id)321*549Smuffin tgetnum(char *id)
3220Sstevel@tonic-gate {
323*549Smuffin int i, base;
324*549Smuffin char *bp = tbuf;
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate for (;;) {
3270Sstevel@tonic-gate bp = tskip(bp);
3280Sstevel@tonic-gate if (*bp == 0)
3290Sstevel@tonic-gate return (-1);
3300Sstevel@tonic-gate if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
3310Sstevel@tonic-gate continue;
3320Sstevel@tonic-gate if (*bp == '@')
3330Sstevel@tonic-gate return (-1);
3340Sstevel@tonic-gate if (*bp != '#')
3350Sstevel@tonic-gate continue;
3360Sstevel@tonic-gate bp++;
3370Sstevel@tonic-gate base = 10;
3380Sstevel@tonic-gate if (*bp == '0')
3390Sstevel@tonic-gate base = 8;
3400Sstevel@tonic-gate i = 0;
3410Sstevel@tonic-gate while (isdigit(*bp))
3420Sstevel@tonic-gate i *= base, i += *bp++ - '0';
3430Sstevel@tonic-gate return (i);
3440Sstevel@tonic-gate }
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate /*
3480Sstevel@tonic-gate * Handle a flag option.
3490Sstevel@tonic-gate * Flag options are given "naked", i.e. followed by a : or the end
3500Sstevel@tonic-gate * of the buffer. Return 1 if we find the option, or 0 if it is
3510Sstevel@tonic-gate * not given.
3520Sstevel@tonic-gate */
353*549Smuffin int
tgetflag(char * id)354*549Smuffin tgetflag(char *id)
3550Sstevel@tonic-gate {
356*549Smuffin char *bp = tbuf;
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate for (;;) {
3590Sstevel@tonic-gate bp = tskip(bp);
3600Sstevel@tonic-gate if (!*bp)
3610Sstevel@tonic-gate return (0);
3620Sstevel@tonic-gate if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
3630Sstevel@tonic-gate if (!*bp || *bp == ':')
3640Sstevel@tonic-gate return (1);
3650Sstevel@tonic-gate else if (*bp == '@')
3660Sstevel@tonic-gate return (0);
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate }
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate
3710Sstevel@tonic-gate /*
3720Sstevel@tonic-gate * Get a string valued option.
3730Sstevel@tonic-gate * These are given as
3740Sstevel@tonic-gate * cl=^Z
3750Sstevel@tonic-gate * Much decoding is done on the strings, and the strings are
3760Sstevel@tonic-gate * placed in area, which is a ref parameter which is updated.
3770Sstevel@tonic-gate * No checking on area overflow.
3780Sstevel@tonic-gate */
3790Sstevel@tonic-gate char *
tgetstr(char * id,char ** area)380*549Smuffin tgetstr(char *id, char **area)
3810Sstevel@tonic-gate {
382*549Smuffin char *bp = tbuf;
3830Sstevel@tonic-gate
3840Sstevel@tonic-gate for (;;) {
3850Sstevel@tonic-gate bp = tskip(bp);
3860Sstevel@tonic-gate if (!*bp)
3870Sstevel@tonic-gate return (0);
3880Sstevel@tonic-gate if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
3890Sstevel@tonic-gate continue;
3900Sstevel@tonic-gate if (*bp == '@')
3910Sstevel@tonic-gate return (0);
3920Sstevel@tonic-gate if (*bp != '=')
3930Sstevel@tonic-gate continue;
3940Sstevel@tonic-gate bp++;
3950Sstevel@tonic-gate return (tdecode(bp, area));
3960Sstevel@tonic-gate }
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate
3990Sstevel@tonic-gate /*
4000Sstevel@tonic-gate * Tdecode does the grung work to decode the
4010Sstevel@tonic-gate * string capability escapes.
4020Sstevel@tonic-gate */
4030Sstevel@tonic-gate static char *
tdecode(char * str,char ** area)404*549Smuffin tdecode(char *str, char **area)
4050Sstevel@tonic-gate {
406*549Smuffin char *cp;
407*549Smuffin int c;
408*549Smuffin char *dp;
4090Sstevel@tonic-gate int i;
4100Sstevel@tonic-gate
4110Sstevel@tonic-gate cp = *area;
412*549Smuffin while ((c = *str++) != 0 && c != ':') {
4130Sstevel@tonic-gate switch (c) {
4140Sstevel@tonic-gate
4150Sstevel@tonic-gate case '^':
4160Sstevel@tonic-gate c = *str++ & 037;
4170Sstevel@tonic-gate break;
4180Sstevel@tonic-gate
4190Sstevel@tonic-gate case '\\':
4200Sstevel@tonic-gate dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
4210Sstevel@tonic-gate c = *str++;
4220Sstevel@tonic-gate nextc:
4230Sstevel@tonic-gate if (*dp++ == c) {
4240Sstevel@tonic-gate c = *dp++;
4250Sstevel@tonic-gate break;
4260Sstevel@tonic-gate }
4270Sstevel@tonic-gate dp++;
4280Sstevel@tonic-gate if (*dp)
4290Sstevel@tonic-gate goto nextc;
4300Sstevel@tonic-gate if (isdigit(c)) {
4310Sstevel@tonic-gate c -= '0', i = 2;
4320Sstevel@tonic-gate do
4330Sstevel@tonic-gate c <<= 3, c |= *str++ - '0';
434*549Smuffin while (--i && isdigit(*str))
435*549Smuffin ;
4360Sstevel@tonic-gate }
4370Sstevel@tonic-gate break;
4380Sstevel@tonic-gate }
4390Sstevel@tonic-gate *cp++ = c;
4400Sstevel@tonic-gate }
4410Sstevel@tonic-gate *cp++ = 0;
4420Sstevel@tonic-gate str = *area;
4430Sstevel@tonic-gate *area = cp;
4440Sstevel@tonic-gate return (str);
4450Sstevel@tonic-gate }
446