xref: /titanic_52/usr/src/cmd/write/write.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
24*7c478bd9Sstevel@tonic-gate 
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate /*
27*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
28*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
29*7c478bd9Sstevel@tonic-gate  */
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include	<ctype.h>
34*7c478bd9Sstevel@tonic-gate #include	<string.h>
35*7c478bd9Sstevel@tonic-gate #include	<stdio.h>
36*7c478bd9Sstevel@tonic-gate #include	<signal.h>
37*7c478bd9Sstevel@tonic-gate #include	<sys/wait.h>
38*7c478bd9Sstevel@tonic-gate #include	<sys/types.h>
39*7c478bd9Sstevel@tonic-gate #include	<sys/stat.h>
40*7c478bd9Sstevel@tonic-gate #include	<sys/utsname.h>
41*7c478bd9Sstevel@tonic-gate #include	<stdlib.h>
42*7c478bd9Sstevel@tonic-gate #include	<unistd.h>
43*7c478bd9Sstevel@tonic-gate #include	<time.h>
44*7c478bd9Sstevel@tonic-gate #include	<utmpx.h>
45*7c478bd9Sstevel@tonic-gate #include	<pwd.h>
46*7c478bd9Sstevel@tonic-gate #include	<fcntl.h>
47*7c478bd9Sstevel@tonic-gate #include	<stdarg.h>
48*7c478bd9Sstevel@tonic-gate #include	<locale.h>
49*7c478bd9Sstevel@tonic-gate #include	<stdlib.h>
50*7c478bd9Sstevel@tonic-gate #include	<limits.h>
51*7c478bd9Sstevel@tonic-gate #include	<wctype.h>
52*7c478bd9Sstevel@tonic-gate #include	<errno.h>
53*7c478bd9Sstevel@tonic-gate #include	<syslog.h>
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate #define		TRUE	1
56*7c478bd9Sstevel@tonic-gate #define		FALSE	0
57*7c478bd9Sstevel@tonic-gate #define		FAILURE	-1
58*7c478bd9Sstevel@tonic-gate #define		DATE_FMT	"%a %b %e %H:%M:%S"
59*7c478bd9Sstevel@tonic-gate #define		UTMP_HACK  /* work around until utmpx is world writable */
60*7c478bd9Sstevel@tonic-gate /*
61*7c478bd9Sstevel@tonic-gate  *	DATE-TIME format
62*7c478bd9Sstevel@tonic-gate  *  %a	abbreviated weekday name
63*7c478bd9Sstevel@tonic-gate  *  %b  abbreviated month name
64*7c478bd9Sstevel@tonic-gate  *  %e  day of month
65*7c478bd9Sstevel@tonic-gate  *  %H  hour - 24 hour clock
66*7c478bd9Sstevel@tonic-gate  *  %M  minute
67*7c478bd9Sstevel@tonic-gate  *  %S  second
68*7c478bd9Sstevel@tonic-gate  *
69*7c478bd9Sstevel@tonic-gate  */
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate static int permit1(int);
72*7c478bd9Sstevel@tonic-gate static int permit(char *);
73*7c478bd9Sstevel@tonic-gate static int readcsi(int, char *, int);
74*7c478bd9Sstevel@tonic-gate static void setsignals();
75*7c478bd9Sstevel@tonic-gate static void shellcmd(char *);
76*7c478bd9Sstevel@tonic-gate static void openfail();
77*7c478bd9Sstevel@tonic-gate static void eof();
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate static struct	utsname utsn;
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate static FILE	*fp;	/* File pointer for receipient's terminal */
82*7c478bd9Sstevel@tonic-gate static char *rterm, *receipient; /* Pointer to receipient's terminal & name */
83*7c478bd9Sstevel@tonic-gate static char *thissys;
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate int
86*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
87*7c478bd9Sstevel@tonic-gate {
88*7c478bd9Sstevel@tonic-gate 	int i;
89*7c478bd9Sstevel@tonic-gate 	struct utmpx *ubuf;
90*7c478bd9Sstevel@tonic-gate 	static struct utmpx self;
91*7c478bd9Sstevel@tonic-gate 	char ownname[sizeof (self.ut_user) + 1];
92*7c478bd9Sstevel@tonic-gate 	static char rterminal[sizeof ("/dev/") + sizeof (self.ut_line)] =
93*7c478bd9Sstevel@tonic-gate 	    "/dev/";
94*7c478bd9Sstevel@tonic-gate 	extern char *rterm, *receipient;
95*7c478bd9Sstevel@tonic-gate 	char *terminal, *ownterminal, *oterminal;
96*7c478bd9Sstevel@tonic-gate 	short count;
97*7c478bd9Sstevel@tonic-gate 	extern FILE *fp;
98*7c478bd9Sstevel@tonic-gate 	char input[134+MB_LEN_MAX];
99*7c478bd9Sstevel@tonic-gate 	char *ptr;
100*7c478bd9Sstevel@tonic-gate 	time_t tod;
101*7c478bd9Sstevel@tonic-gate 	char time_buf[40];
102*7c478bd9Sstevel@tonic-gate 	struct passwd *passptr;
103*7c478bd9Sstevel@tonic-gate 	char badterm[20][20];
104*7c478bd9Sstevel@tonic-gate 	int bad = 0;
105*7c478bd9Sstevel@tonic-gate 	uid_t	myuid;
106*7c478bd9Sstevel@tonic-gate 	char *bp;
107*7c478bd9Sstevel@tonic-gate 	int n;
108*7c478bd9Sstevel@tonic-gate 	wchar_t wc;
109*7c478bd9Sstevel@tonic-gate 	int c;
110*7c478bd9Sstevel@tonic-gate 	int newline;
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
113*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
114*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
115*7c478bd9Sstevel@tonic-gate #endif
116*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "")) != EOF)
119*7c478bd9Sstevel@tonic-gate 		switch (c) {
120*7c478bd9Sstevel@tonic-gate 			case '?':
121*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "Usage: write %s\n",
122*7c478bd9Sstevel@tonic-gate 				gettext("user_name [terminal]"));
123*7c478bd9Sstevel@tonic-gate 				exit(2);
124*7c478bd9Sstevel@tonic-gate 		}
125*7c478bd9Sstevel@tonic-gate 	myuid = geteuid();
126*7c478bd9Sstevel@tonic-gate 	uname(&utsn);
127*7c478bd9Sstevel@tonic-gate 	thissys = utsn.nodename;
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate /*	Set "rterm" to location where receipient's terminal will go.	*/
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate 	rterm = &rterminal[sizeof ("/dev/") - 1];
132*7c478bd9Sstevel@tonic-gate 	terminal = NULL;
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate 	if (--argc <= 0) {
135*7c478bd9Sstevel@tonic-gate 	    (void) fprintf(stderr, "Usage: write %s\n",
136*7c478bd9Sstevel@tonic-gate 		gettext("user_name [terminal]"));
137*7c478bd9Sstevel@tonic-gate 	    exit(1);
138*7c478bd9Sstevel@tonic-gate 	    }
139*7c478bd9Sstevel@tonic-gate 	else
140*7c478bd9Sstevel@tonic-gate 	    {
141*7c478bd9Sstevel@tonic-gate 	    receipient = *++argv;
142*7c478bd9Sstevel@tonic-gate 	    }
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate /*	Was a terminal name supplied?  If so, save it.			*/
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate 	if (--argc > 1) {
147*7c478bd9Sstevel@tonic-gate 	    (void) fprintf(stderr, "Usage: write %s\n",
148*7c478bd9Sstevel@tonic-gate 		gettext("user_name [terminal]"));
149*7c478bd9Sstevel@tonic-gate 	    exit(1);
150*7c478bd9Sstevel@tonic-gate 	} else {
151*7c478bd9Sstevel@tonic-gate 	    terminal = *++argv;
152*7c478bd9Sstevel@tonic-gate 	}
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate /*	One of the standard file descriptors must be attached to a	*/
155*7c478bd9Sstevel@tonic-gate /*	terminal in "/dev".						*/
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 	if ((ownterminal = ttyname(fileno(stdin))) == NULL &&
158*7c478bd9Sstevel@tonic-gate 	    (ownterminal = ttyname(fileno(stdout))) == NULL &&
159*7c478bd9Sstevel@tonic-gate 	    (ownterminal = ttyname(fileno(stderr))) == NULL) {
160*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
161*7c478bd9Sstevel@tonic-gate 			gettext("I cannot determine your terminal name."
162*7c478bd9Sstevel@tonic-gate 					" No reply possible.\n"));
163*7c478bd9Sstevel@tonic-gate 		ownterminal = "/dev/???";
164*7c478bd9Sstevel@tonic-gate 	}
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate 	/*
167*7c478bd9Sstevel@tonic-gate 	 * Set "ownterminal" past the "/dev/" at the beginning of
168*7c478bd9Sstevel@tonic-gate 	 * the device name.
169*7c478bd9Sstevel@tonic-gate 	 */
170*7c478bd9Sstevel@tonic-gate 	oterminal = ownterminal + sizeof ("/dev/")-1;
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 	/*
173*7c478bd9Sstevel@tonic-gate 	 * Scan through the "utmpx" file for your own entry and the
174*7c478bd9Sstevel@tonic-gate 	 * entry for the person we want to send to.
175*7c478bd9Sstevel@tonic-gate 	 */
176*7c478bd9Sstevel@tonic-gate 	for (self.ut_pid = 0, count = 0; (ubuf = getutxent()) != NULL; ) {
177*7c478bd9Sstevel@tonic-gate 	/* Is this a USER_PROCESS entry? */
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate 	    if (ubuf->ut_type == USER_PROCESS) {
180*7c478bd9Sstevel@tonic-gate /*	Is it our entry?  (ie.  The line matches ours?)			*/
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 		if (strncmp(&ubuf->ut_line[0], oterminal,
183*7c478bd9Sstevel@tonic-gate 		    sizeof (ubuf->ut_line)) == 0) self = *ubuf;
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate /*	Is this the person we want to send to?				*/
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate 		if (strncmp(receipient, &ubuf->ut_user[0],
188*7c478bd9Sstevel@tonic-gate 		    sizeof (ubuf->ut_user)) == 0) {
189*7c478bd9Sstevel@tonic-gate /*	If a terminal name was supplied, is this login at the correct	*/
190*7c478bd9Sstevel@tonic-gate /*	terminal?  If not, ignore.  If it is right place, copy over the	*/
191*7c478bd9Sstevel@tonic-gate /*	name.								*/
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 		    if (terminal != NULL) {
194*7c478bd9Sstevel@tonic-gate 			if (strncmp(terminal, &ubuf->ut_line[0],
195*7c478bd9Sstevel@tonic-gate 			    sizeof (ubuf->ut_line)) == 0) {
196*7c478bd9Sstevel@tonic-gate 			    strlcpy(rterm, &ubuf->ut_line[0],
197*7c478bd9Sstevel@tonic-gate 				sizeof (rterminal) - (rterm - rterminal));
198*7c478bd9Sstevel@tonic-gate 			    if (myuid && !permit(rterminal)) {
199*7c478bd9Sstevel@tonic-gate 				bad++;
200*7c478bd9Sstevel@tonic-gate 				rterm[0] = '\0';
201*7c478bd9Sstevel@tonic-gate 			    }
202*7c478bd9Sstevel@tonic-gate 			    }
203*7c478bd9Sstevel@tonic-gate 		    }
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate /*	If no terminal was supplied, then take this terminal if no	*/
206*7c478bd9Sstevel@tonic-gate /*	other terminal has been encountered already.			*/
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 		    else
209*7c478bd9Sstevel@tonic-gate 		    {
210*7c478bd9Sstevel@tonic-gate /*	If this is the first encounter, copy the string into		*/
211*7c478bd9Sstevel@tonic-gate /*	"rterminal".							*/
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 			if (*rterm == '\0') {
214*7c478bd9Sstevel@tonic-gate 			    strlcpy(rterm, &ubuf->ut_line[0],
215*7c478bd9Sstevel@tonic-gate 				sizeof (rterminal) - (rterm - rterminal));
216*7c478bd9Sstevel@tonic-gate 			    if (myuid && !permit(rterminal)) {
217*7c478bd9Sstevel@tonic-gate 				if (bad < 20) {
218*7c478bd9Sstevel@tonic-gate 					strlcpy(badterm[bad++], rterm,
219*7c478bd9Sstevel@tonic-gate 					    sizeof (badterm[bad++]));
220*7c478bd9Sstevel@tonic-gate 				}
221*7c478bd9Sstevel@tonic-gate 				rterm[0] = '\0';
222*7c478bd9Sstevel@tonic-gate 			    } else if (bad > 0) {
223*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
224*7c478bd9Sstevel@tonic-gate 				gettext(
225*7c478bd9Sstevel@tonic-gate 				"%s is logged on more than one place.\n"
226*7c478bd9Sstevel@tonic-gate 	"You are connected to \"%s\".\nOther locations are:\n"),
227*7c478bd9Sstevel@tonic-gate 				    receipient, rterm);
228*7c478bd9Sstevel@tonic-gate 				for (i = 0; i < bad; i++)
229*7c478bd9Sstevel@tonic-gate 				    (void) fprintf(stderr, "%s\n", badterm[i]);
230*7c478bd9Sstevel@tonic-gate 			    }
231*7c478bd9Sstevel@tonic-gate 			}
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate /*	If this is the second terminal, print out the first.  In all	*/
234*7c478bd9Sstevel@tonic-gate /*	cases of multiple terminals, list out all the other terminals	*/
235*7c478bd9Sstevel@tonic-gate /*	so the user can restart knowing what her/his choices are.	*/
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 			else if (terminal == NULL) {
238*7c478bd9Sstevel@tonic-gate 			    if (count == 1 && bad == 0) {
239*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
240*7c478bd9Sstevel@tonic-gate 				gettext(
241*7c478bd9Sstevel@tonic-gate 				"%s is logged on more than one place.\n"
242*7c478bd9Sstevel@tonic-gate 	"You are connected to \"%s\".\nOther locations are:\n"),
243*7c478bd9Sstevel@tonic-gate 				    receipient, rterm);
244*7c478bd9Sstevel@tonic-gate 			    }
245*7c478bd9Sstevel@tonic-gate 			    fwrite(&ubuf->ut_line[0], sizeof (ubuf->ut_line),
246*7c478bd9Sstevel@tonic-gate 				1, stderr);
247*7c478bd9Sstevel@tonic-gate 			    (void) fprintf(stderr, "\n");
248*7c478bd9Sstevel@tonic-gate 			    }
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 			count++;
251*7c478bd9Sstevel@tonic-gate 		    }			/* End of "else" */
252*7c478bd9Sstevel@tonic-gate 		    }			/* End of "else if (strncmp" */
253*7c478bd9Sstevel@tonic-gate 	    }			/* End of "if (USER_PROCESS" */
254*7c478bd9Sstevel@tonic-gate 	    }		/* End of "for(count=0" */
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate /*	Did we find a place to talk to?  If we were looking for a	*/
257*7c478bd9Sstevel@tonic-gate /*	specific spot and didn't find it, complain and quit.		*/
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 	if (terminal != NULL && *rterm == '\0') {
260*7c478bd9Sstevel@tonic-gate 	    if (bad > 0) {
261*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Permission denied.\n"));
262*7c478bd9Sstevel@tonic-gate 		exit(1);
263*7c478bd9Sstevel@tonic-gate 		} else {
264*7c478bd9Sstevel@tonic-gate #ifdef UTMP_HACK
265*7c478bd9Sstevel@tonic-gate 		if (strlcat(rterminal, terminal, sizeof (rterminal)) >=
266*7c478bd9Sstevel@tonic-gate 		    sizeof (rterminal)) {
267*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
268*7c478bd9Sstevel@tonic-gate 			    gettext("Terminal name too long.\n"));
269*7c478bd9Sstevel@tonic-gate 			exit(1);
270*7c478bd9Sstevel@tonic-gate 		}
271*7c478bd9Sstevel@tonic-gate 		if (self.ut_pid == 0) {
272*7c478bd9Sstevel@tonic-gate 			if ((passptr = getpwuid(getuid())) == NULL) {
273*7c478bd9Sstevel@tonic-gate 			    (void) fprintf(stderr,
274*7c478bd9Sstevel@tonic-gate 				gettext("Cannot determine who you are.\n"));
275*7c478bd9Sstevel@tonic-gate 			    exit(1);
276*7c478bd9Sstevel@tonic-gate 		    }
277*7c478bd9Sstevel@tonic-gate 		    (void) strlcpy(&ownname[0], &passptr->pw_name[0],
278*7c478bd9Sstevel@tonic-gate 			sizeof (ownname));
279*7c478bd9Sstevel@tonic-gate 		} else {
280*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(&ownname[0], self.ut_user,
281*7c478bd9Sstevel@tonic-gate 			    sizeof (self.ut_user));
282*7c478bd9Sstevel@tonic-gate 		}
283*7c478bd9Sstevel@tonic-gate 		if (!permit(rterminal)) {
284*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
285*7c478bd9Sstevel@tonic-gate 				gettext("%s permission denied\n"), terminal);
286*7c478bd9Sstevel@tonic-gate 			exit(1);
287*7c478bd9Sstevel@tonic-gate 		}
288*7c478bd9Sstevel@tonic-gate #else
289*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s is not at \"%s\".\n"),
290*7c478bd9Sstevel@tonic-gate 			receipient, terminal);
291*7c478bd9Sstevel@tonic-gate 		exit(1);
292*7c478bd9Sstevel@tonic-gate #endif	/* UTMP_HACK */
293*7c478bd9Sstevel@tonic-gate 	    }
294*7c478bd9Sstevel@tonic-gate 	    }
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate /*	If we were just looking for anyplace to talk and didn't find	*/
297*7c478bd9Sstevel@tonic-gate /*	one, complain and quit.						*/
298*7c478bd9Sstevel@tonic-gate /*	If permissions prevent us from sending to this person - exit	*/
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate 	else if (*rterm == '\0') {
301*7c478bd9Sstevel@tonic-gate 	    if (bad > 0)
302*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Permission denied.\n"));
303*7c478bd9Sstevel@tonic-gate 	    else
304*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
305*7c478bd9Sstevel@tonic-gate 			gettext("%s is not logged on.\n"), receipient);
306*7c478bd9Sstevel@tonic-gate 	    exit(1);
307*7c478bd9Sstevel@tonic-gate 	    }
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate /*	Did we find our own entry?					*/
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	else if (self.ut_pid == 0) {
312*7c478bd9Sstevel@tonic-gate /*	Use the user id instead of utmp name if the entry in the	*/
313*7c478bd9Sstevel@tonic-gate /*	utmp file couldn't be found.					*/
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	    if ((passptr = getpwuid(getuid())) == (struct passwd *)NULL) {
316*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
317*7c478bd9Sstevel@tonic-gate 			gettext("Cannot determine who you are.\n"));
318*7c478bd9Sstevel@tonic-gate 		exit(1);
319*7c478bd9Sstevel@tonic-gate 	    }
320*7c478bd9Sstevel@tonic-gate 	    strncpy(&ownname[0], &passptr->pw_name[0], sizeof (ownname));
321*7c478bd9Sstevel@tonic-gate 	    }
322*7c478bd9Sstevel@tonic-gate 	else
323*7c478bd9Sstevel@tonic-gate 	    {
324*7c478bd9Sstevel@tonic-gate 	    strncpy(&ownname[0], self.ut_user, sizeof (self.ut_user));
325*7c478bd9Sstevel@tonic-gate 	    }
326*7c478bd9Sstevel@tonic-gate 	ownname[sizeof (ownname)-1] = '\0';
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 	if (!permit1(1))
329*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
330*7c478bd9Sstevel@tonic-gate 		gettext("Warning: You have your terminal set to \"mesg -n\"."
331*7c478bd9Sstevel@tonic-gate 		    " No reply possible.\n"));
332*7c478bd9Sstevel@tonic-gate /*	Close the utmpx files.						*/
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 	endutxent();
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate /*	Try to open up the line to the receipient's terminal.		*/
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 	signal(SIGALRM, openfail);
339*7c478bd9Sstevel@tonic-gate 	alarm(5);
340*7c478bd9Sstevel@tonic-gate 	fp = fopen(&rterminal[0], "w");
341*7c478bd9Sstevel@tonic-gate 	alarm(0);
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate /*	Make sure executed subshell doesn't inherit this fd - close-on-exec */
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 	if (fcntl(fileno(fp), F_SETFD, FD_CLOEXEC) < 0)  {
346*7c478bd9Sstevel@tonic-gate 		perror("fcntl(F_SETFD)");
347*7c478bd9Sstevel@tonic-gate 		exit(1);
348*7c478bd9Sstevel@tonic-gate 	}
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate /*	Catch signals SIGHUP, SIGINT, SIGQUIT, and SIGTERM, and send	*/
351*7c478bd9Sstevel@tonic-gate /*	<EOT> message to receipient before dying away.			*/
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate 	setsignals(eof);
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate /*	Get the time of day, convert it to a string and throw away the	*/
356*7c478bd9Sstevel@tonic-gate /*	year information at the end of the string.			*/
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 	time(&tod);
359*7c478bd9Sstevel@tonic-gate 	(void) strftime(time_buf, sizeof (time_buf),
360*7c478bd9Sstevel@tonic-gate 	    dcgettext(NULL, DATE_FMT, LC_TIME), localtime(&tod));
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	(void) fprintf(fp,
363*7c478bd9Sstevel@tonic-gate 	gettext("\n\007\007\007\tMessage from %s on %s (%s) [ %s ] ...\n"),
364*7c478bd9Sstevel@tonic-gate 	    &ownname[0], thissys, oterminal, time_buf);
365*7c478bd9Sstevel@tonic-gate 	fflush(fp);
366*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\007\007");
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate /*	Get input from user and send to receipient unless it begins	*/
369*7c478bd9Sstevel@tonic-gate /*	with a !, when it is to be a shell command.			*/
370*7c478bd9Sstevel@tonic-gate 	newline = 1;
371*7c478bd9Sstevel@tonic-gate 	while ((i = readcsi(0, &input[0], sizeof (input))) > 0) {
372*7c478bd9Sstevel@tonic-gate 		ptr = &input[0];
373*7c478bd9Sstevel@tonic-gate /*	Is this a shell command?					*/
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 		if ((newline) && (*ptr == '!'))
376*7c478bd9Sstevel@tonic-gate 			shellcmd(++ptr);
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate /*	Send line to the receipient.					*/
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 		else {
381*7c478bd9Sstevel@tonic-gate 			if (myuid && !permit1(fileno(fp))) {
382*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
383*7c478bd9Sstevel@tonic-gate 			gettext("Can no longer write to %s\n"), rterminal);
384*7c478bd9Sstevel@tonic-gate 				break;
385*7c478bd9Sstevel@tonic-gate 			}
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate /*
388*7c478bd9Sstevel@tonic-gate  * All non-printable characters are displayed using a special notation:
389*7c478bd9Sstevel@tonic-gate  * Control characters  shall be displayed using the two character
390*7c478bd9Sstevel@tonic-gate  * sequence of ^ (carat) and the ASCII character - decimal 64 greater
391*7c478bd9Sstevel@tonic-gate  * that the character being encoded - eg., a \003 is displayed ^C.
392*7c478bd9Sstevel@tonic-gate  * Characters with the eighth bit set shall be displayed using
393*7c478bd9Sstevel@tonic-gate  * the three or four character meta notation - e.g., \372 is
394*7c478bd9Sstevel@tonic-gate  * displayed M-z and \203 is displayed M-^C.
395*7c478bd9Sstevel@tonic-gate  */
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 			newline = 0;
398*7c478bd9Sstevel@tonic-gate 			for (bp = &input[0]; --i >= 0; bp++) {
399*7c478bd9Sstevel@tonic-gate 			if (*bp == '\n') {
400*7c478bd9Sstevel@tonic-gate 				newline = 1;
401*7c478bd9Sstevel@tonic-gate 				putc('\r', fp);
402*7c478bd9Sstevel@tonic-gate 			}
403*7c478bd9Sstevel@tonic-gate 			if (*bp == ' ' ||
404*7c478bd9Sstevel@tonic-gate 				 *bp == '\t' || *bp == '\n' ||
405*7c478bd9Sstevel@tonic-gate 				 *bp == '\r' || *bp == '\013' ||
406*7c478bd9Sstevel@tonic-gate 				 *bp == '\007') {
407*7c478bd9Sstevel@tonic-gate 					putc(*bp, fp);
408*7c478bd9Sstevel@tonic-gate 			} else if (((n = mbtowc(&wc, bp, MB_CUR_MAX)) > 0) &&
409*7c478bd9Sstevel@tonic-gate 				iswprint(wc)) {
410*7c478bd9Sstevel@tonic-gate 				for (; n > 0; --n, --i, ++bp)
411*7c478bd9Sstevel@tonic-gate 					putc(*bp, fp);
412*7c478bd9Sstevel@tonic-gate 				bp--, ++i;
413*7c478bd9Sstevel@tonic-gate 			} else {
414*7c478bd9Sstevel@tonic-gate 				if (!isascii(*bp)) {
415*7c478bd9Sstevel@tonic-gate 					fputs("M-", fp);
416*7c478bd9Sstevel@tonic-gate 					*bp = toascii(*bp);
417*7c478bd9Sstevel@tonic-gate 				}
418*7c478bd9Sstevel@tonic-gate 				if (iscntrl(*bp)) {
419*7c478bd9Sstevel@tonic-gate 					putc('^', fp);
420*7c478bd9Sstevel@tonic-gate /*	add decimal 64 to the control character			*/
421*7c478bd9Sstevel@tonic-gate 					putc(*bp + 0100, fp);
422*7c478bd9Sstevel@tonic-gate 				}
423*7c478bd9Sstevel@tonic-gate 				else
424*7c478bd9Sstevel@tonic-gate 					putc(*bp, fp);
425*7c478bd9Sstevel@tonic-gate 			}
426*7c478bd9Sstevel@tonic-gate 			if (*bp == '\n')
427*7c478bd9Sstevel@tonic-gate 				fflush(fp);
428*7c478bd9Sstevel@tonic-gate 			if (ferror(fp) || feof(fp)) {
429*7c478bd9Sstevel@tonic-gate 				printf(gettext(
430*7c478bd9Sstevel@tonic-gate 				"\n\007Write failed (%s logged out?)\n"),
431*7c478bd9Sstevel@tonic-gate 				receipient);
432*7c478bd9Sstevel@tonic-gate 				exit(1);
433*7c478bd9Sstevel@tonic-gate 			}
434*7c478bd9Sstevel@tonic-gate 			} /* for */
435*7c478bd9Sstevel@tonic-gate 			fflush(fp);
436*7c478bd9Sstevel@tonic-gate 	} /* else */
437*7c478bd9Sstevel@tonic-gate 	} /* while */
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate /*	Since "end of file" received, send <EOT> message to receipient.	*/
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 	eof();
442*7c478bd9Sstevel@tonic-gate 	return (0);
443*7c478bd9Sstevel@tonic-gate }
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate static void
447*7c478bd9Sstevel@tonic-gate setsignals(catch)
448*7c478bd9Sstevel@tonic-gate void (*catch)();
449*7c478bd9Sstevel@tonic-gate {
450*7c478bd9Sstevel@tonic-gate 	signal(SIGHUP, catch);
451*7c478bd9Sstevel@tonic-gate 	signal(SIGINT, catch);
452*7c478bd9Sstevel@tonic-gate 	signal(SIGQUIT, catch);
453*7c478bd9Sstevel@tonic-gate 	signal(SIGTERM, catch);
454*7c478bd9Sstevel@tonic-gate }
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate static void
458*7c478bd9Sstevel@tonic-gate shellcmd(command)
459*7c478bd9Sstevel@tonic-gate char *command;
460*7c478bd9Sstevel@tonic-gate {
461*7c478bd9Sstevel@tonic-gate 	register pid_t child;
462*7c478bd9Sstevel@tonic-gate 	extern void eof();
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 	if ((child = fork()) == (pid_t)FAILURE)
465*7c478bd9Sstevel@tonic-gate 	    {
466*7c478bd9Sstevel@tonic-gate 	    (void) fprintf(stderr,
467*7c478bd9Sstevel@tonic-gate 	    gettext("Unable to fork.  Try again later.\n"));
468*7c478bd9Sstevel@tonic-gate 	    return;
469*7c478bd9Sstevel@tonic-gate 	    } else if (child == (pid_t)0) {
470*7c478bd9Sstevel@tonic-gate /*	Reset the signals to the default actions and exec a shell.	*/
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate 	    if (setgid(getgid()) < 0)
473*7c478bd9Sstevel@tonic-gate 		exit(1);
474*7c478bd9Sstevel@tonic-gate 	    execl("/usr/bin/sh", "sh", "-c", command, 0);
475*7c478bd9Sstevel@tonic-gate 	    exit(0);
476*7c478bd9Sstevel@tonic-gate 	    }
477*7c478bd9Sstevel@tonic-gate 	else
478*7c478bd9Sstevel@tonic-gate 	    {
479*7c478bd9Sstevel@tonic-gate /*	Allow user to type <del> and <quit> without dying during	*/
480*7c478bd9Sstevel@tonic-gate /*	commands.							*/
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 	    signal(SIGINT, SIG_IGN);
483*7c478bd9Sstevel@tonic-gate 	    signal(SIGQUIT, SIG_IGN);
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate /*	As parent wait around for user to finish spunoff command.	*/
486*7c478bd9Sstevel@tonic-gate 
487*7c478bd9Sstevel@tonic-gate 	    while (wait(NULL) != child);
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate /*	Reset the signals to their normal state.			*/
490*7c478bd9Sstevel@tonic-gate 
491*7c478bd9Sstevel@tonic-gate 	    setsignals(eof);
492*7c478bd9Sstevel@tonic-gate 	    }
493*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stdout, "!\n");
494*7c478bd9Sstevel@tonic-gate }
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate static void
497*7c478bd9Sstevel@tonic-gate openfail()
498*7c478bd9Sstevel@tonic-gate {
499*7c478bd9Sstevel@tonic-gate 	extern char *rterm, *receipient;
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
502*7c478bd9Sstevel@tonic-gate 		gettext("Timeout trying to open %s's line(%s).\n"),
503*7c478bd9Sstevel@tonic-gate 	    receipient, rterm);
504*7c478bd9Sstevel@tonic-gate 	exit(1);
505*7c478bd9Sstevel@tonic-gate }
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate static void
508*7c478bd9Sstevel@tonic-gate eof()
509*7c478bd9Sstevel@tonic-gate {
510*7c478bd9Sstevel@tonic-gate 	extern FILE *fp;
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "%s\n", gettext("<EOT>"));
513*7c478bd9Sstevel@tonic-gate 	exit(0);
514*7c478bd9Sstevel@tonic-gate }
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate /*
517*7c478bd9Sstevel@tonic-gate  * permit: check mode of terminal - if not writable by all disallow writing to
518*7c478bd9Sstevel@tonic-gate  * (even the user him/herself cannot therefore write to their own tty)
519*7c478bd9Sstevel@tonic-gate  */
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate static int
522*7c478bd9Sstevel@tonic-gate permit(term)
523*7c478bd9Sstevel@tonic-gate char *term;
524*7c478bd9Sstevel@tonic-gate {
525*7c478bd9Sstevel@tonic-gate 	struct stat buf;
526*7c478bd9Sstevel@tonic-gate 	int fildes;
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 	if ((fildes = open(term, O_WRONLY|O_NOCTTY)) < 0)
529*7c478bd9Sstevel@tonic-gate 		return (0);
530*7c478bd9Sstevel@tonic-gate 	/* check if the device really is a tty */
531*7c478bd9Sstevel@tonic-gate 	if (!isatty(fildes)) {
532*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
533*7c478bd9Sstevel@tonic-gate 		    gettext("%s in utmpx is not a tty\n"), term);
534*7c478bd9Sstevel@tonic-gate 		openlog("write", 0, LOG_AUTH);
535*7c478bd9Sstevel@tonic-gate 		syslog(LOG_CRIT, "%s in utmpx is not a tty\n", term);
536*7c478bd9Sstevel@tonic-gate 		closelog();
537*7c478bd9Sstevel@tonic-gate 		close(fildes);
538*7c478bd9Sstevel@tonic-gate 		return (0);
539*7c478bd9Sstevel@tonic-gate 	}
540*7c478bd9Sstevel@tonic-gate 	fstat(fildes, &buf);
541*7c478bd9Sstevel@tonic-gate 	close(fildes);
542*7c478bd9Sstevel@tonic-gate 	return (buf.st_mode & (S_IWGRP|S_IWOTH));
543*7c478bd9Sstevel@tonic-gate }
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate /*
548*7c478bd9Sstevel@tonic-gate  * permit1: check mode of terminal - if not writable by all disallow writing
549*7c478bd9Sstevel@tonic-gate  * to (even the user him/herself cannot therefore write to their own tty)
550*7c478bd9Sstevel@tonic-gate  */
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate /* this is used with fstat (which is faster than stat) where possible */
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate static int
555*7c478bd9Sstevel@tonic-gate permit1(fildes)
556*7c478bd9Sstevel@tonic-gate int fildes;
557*7c478bd9Sstevel@tonic-gate {
558*7c478bd9Sstevel@tonic-gate 	struct stat buf;
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 	fstat(fildes, &buf);
561*7c478bd9Sstevel@tonic-gate 	return (buf.st_mode & (S_IWGRP|S_IWOTH));
562*7c478bd9Sstevel@tonic-gate }
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate /*
566*7c478bd9Sstevel@tonic-gate  * Read a string of multi-byte characters from specified file.
567*7c478bd9Sstevel@tonic-gate  * The requested # of bytes are attempted to read.
568*7c478bd9Sstevel@tonic-gate  * readcsi() tries to complete the last multibyte character
569*7c478bd9Sstevel@tonic-gate  * by calling mbtowc(), if the leftovers form mbtowc(),
570*7c478bd9Sstevel@tonic-gate  * left the last char imcomplete, moves into delta_spool to use later,
571*7c478bd9Sstevel@tonic-gate  * next called. The caller must reserve
572*7c478bd9Sstevel@tonic-gate  * nbytereq+MB_LEN_MAX bytes for the buffer.  When the attempt
573*7c478bd9Sstevel@tonic-gate  * is failed, it truncate the last char.
574*7c478bd9Sstevel@tonic-gate  * Returns the number of bytes that constitutes the valid multi-byte characters.
575*7c478bd9Sstevel@tonic-gate  */
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate static int readcsi(d, buf, nbytereq)
579*7c478bd9Sstevel@tonic-gate int	d;
580*7c478bd9Sstevel@tonic-gate char	*buf;
581*7c478bd9Sstevel@tonic-gate int	nbytereq;
582*7c478bd9Sstevel@tonic-gate {
583*7c478bd9Sstevel@tonic-gate 	static char	delta_pool[MB_LEN_MAX * 2];
584*7c478bd9Sstevel@tonic-gate 	static char	delta_size;
585*7c478bd9Sstevel@tonic-gate 	char	*cp, *nextp, *lastp;
586*7c478bd9Sstevel@tonic-gate 	int	n;
587*7c478bd9Sstevel@tonic-gate 	int	r_size;
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate 	if (delta_size) {
590*7c478bd9Sstevel@tonic-gate 		memcpy(buf, delta_pool, delta_size);
591*7c478bd9Sstevel@tonic-gate 		cp = buf + delta_size;
592*7c478bd9Sstevel@tonic-gate 		r_size = nbytereq - delta_size;
593*7c478bd9Sstevel@tonic-gate 	} else {
594*7c478bd9Sstevel@tonic-gate 		cp = buf;
595*7c478bd9Sstevel@tonic-gate 		r_size = nbytereq;
596*7c478bd9Sstevel@tonic-gate 	}
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate 	if ((r_size = read(d, cp, r_size)) < 0)
599*7c478bd9Sstevel@tonic-gate 		r_size = 0;
600*7c478bd9Sstevel@tonic-gate 	if ((n = delta_size + r_size) <= 0)
601*7c478bd9Sstevel@tonic-gate 		return (n);
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate 	/* Scan the result to test the completeness of each EUC characters. */
604*7c478bd9Sstevel@tonic-gate 	nextp = buf;
605*7c478bd9Sstevel@tonic-gate 	lastp = buf + n; /* Lastp points to the first junk byte. */
606*7c478bd9Sstevel@tonic-gate 	while (nextp < lastp) {
607*7c478bd9Sstevel@tonic-gate 		if ((n = (lastp - nextp)) > (unsigned int)MB_CUR_MAX)
608*7c478bd9Sstevel@tonic-gate 			n = (unsigned int)MB_CUR_MAX;
609*7c478bd9Sstevel@tonic-gate 		if ((n = mbtowc((wchar_t *)0, nextp, n)) <= 0) {
610*7c478bd9Sstevel@tonic-gate 			if ((lastp - nextp) < (unsigned int)MB_CUR_MAX)
611*7c478bd9Sstevel@tonic-gate 				break;
612*7c478bd9Sstevel@tonic-gate 			n = 1;
613*7c478bd9Sstevel@tonic-gate 		}
614*7c478bd9Sstevel@tonic-gate 		nextp += n;
615*7c478bd9Sstevel@tonic-gate 	}
616*7c478bd9Sstevel@tonic-gate 	/* How many bytes needed to complete the last char? */
617*7c478bd9Sstevel@tonic-gate 	delta_size = lastp - nextp;
618*7c478bd9Sstevel@tonic-gate 	if (delta_size > 0) {
619*7c478bd9Sstevel@tonic-gate 		if (nextp[delta_size - 1] != '\n') {
620*7c478bd9Sstevel@tonic-gate 			/* the remnants store into delta_pool */
621*7c478bd9Sstevel@tonic-gate 			memcpy(delta_pool, nextp, delta_size);
622*7c478bd9Sstevel@tonic-gate 		} else
623*7c478bd9Sstevel@tonic-gate 			nextp = lastp;
624*7c478bd9Sstevel@tonic-gate 	}
625*7c478bd9Sstevel@tonic-gate 	*nextp = '\0';
626*7c478bd9Sstevel@tonic-gate 	return (nextp-buf); /* Return # of bytes. */
627*7c478bd9Sstevel@tonic-gate }
628