xref: /illumos-gate/usr/src/cmd/bnu/eio.c (revision 42b53e0fbc5c05289c3d334bb864b784fafe5ce4)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27 /*	  All Rights Reserved  	*/
28 
29 #include "uucp.h"
30 
31 #ifdef	E_PROTOCOL
32 
33 #ifndef MIN
34 #define     MIN(a,b) (((a)<(b))?(a):(b))
35 #endif
36 
37 #if defined(BSD4_2) || defined (ATTSVR4)
38 #include <netinet/in.h>
39 #endif /* BSD4_2 || ATTSVR4 */
40 
41 #define	EBUFSIZ	1024
42 #define	EMESGLEN 20
43 
44 #define TBUFSIZE 1024
45 #define TPACKSIZE	512
46 
47 extern long lseek();	/* Find offset into the file. */
48 static jmp_buf Failbuf;
49 extern int erdblk();
50 extern unsigned msgtime;
51 
52 static char Erdstash[EBUFSIZ];
53 static int Erdlen;
54 
55 /*
56  * error-free channel protocol
57  */
58 /* ARGSUSED */
59 static void
60 ealarm(sig)
61 int sig;
62 {
63 	longjmp(Failbuf, 1);
64 }
65 static void (*esig)();
66 
67 /*
68  * turn on protocol timer
69  */
70 int
71 eturnon()
72 {
73 	esig=signal(SIGALRM, ealarm);
74 	return(0);
75 }
76 
77 int
78 eturnoff()
79 {
80 	signal(SIGALRM, esig);
81 	return(0);
82 }
83 
84 /*
85  * write message across link
86  *	type	-> message type
87  *	str	-> message body (ascii string)
88  *	fn	-> link file descriptor
89  * return
90  *	FAIL	-> write failed
91  *	SUCCESS	-> write succeeded
92  */
93 int
94 ewrmsg(type, str, fn)
95 char *str;
96 int fn;
97 char type;
98 {
99 	return(etwrmsg(type, str, fn, 0));
100 }
101 
102 /*
103  * read message from link
104  *	str	-> message buffer
105  *	fn	-> file descriptor
106  * return
107  *	FAIL	-> read timed out
108  *	SUCCESS	-> ok message in str
109  */
110 int
111 erdmsg(str, fn)
112 char *str;
113 {
114 	return(etrdmsg(str, fn, 0));
115 }
116 
117 /*
118  * read data from file fp1 and write
119  * on link
120  *	fp1	-> file descriptor
121  *	fn	-> link descriptor
122  * returns:
123  *	FAIL	->failure in link
124  *	SUCCESS	-> ok
125  */
126 int
127 ewrdata(fp1, fn)
128 FILE *fp1;
129 int	fn;
130 {
131 	int ret;
132 	int	fd1;
133 	int len;
134 	unsigned long bytes;
135 	char bufr[EBUFSIZ];
136 	struct stat	statbuf;
137 	off_t	msglen;
138 	char	cmsglen[EMESGLEN];
139 	off_t	startPoint;	/* Offset from begining of the file in
140 				 *   case we are restarting from a check
141 				 *   point.
142 				 */
143 
144 	if (setjmp(Failbuf)) {
145 		DEBUG(7, "ewrdata failed\n%s", "");
146 		return(FAIL);
147 	}
148 	bytes = 0L;
149 	fd1 = fileno(fp1);
150 	fstat(fd1, &statbuf);
151 	startPoint = lseek(fd1, 0L, 1);
152 	if (startPoint < 0)
153 	{
154 		DEBUG(7, "ewrdata lseek failed.  Errno=%d\n", errno);
155 		return(FAIL);
156 	}
157 	msglen = statbuf.st_size - startPoint;
158 	if (msglen < 0)
159 	{
160 		DEBUG(7, "ewrdata: startPoint past end of file.\n%s", "");
161 		return(FAIL);
162 	}
163 	sprintf(cmsglen, "%ld", (long) msglen);
164 	DEBUG(9, "ewrdata writing %d ...", sizeof(cmsglen));
165 	alarm(msgtime);
166 	ret = (*Write)(fn, cmsglen, sizeof(cmsglen));
167 	alarm(0);
168 	DEBUG(9, "ret %d\n", ret);
169 	if (ret != sizeof(cmsglen))
170 		return(FAIL);
171 	DEBUG(7, "ewrdata planning to send %ld bytes to remote.\n", msglen);
172 	while ((len = read( fd1, bufr, EBUFSIZ )) > 0) {
173 		DEBUG(9, "ewrdata writing %d ...", len);
174 		alarm(msgtime);
175 		bytes += len;
176 		putfilesize(bytes);
177 		ret = (*Write)(fn, bufr, (unsigned) len);
178 		alarm(0);
179 		DEBUG(9, "ewrdata ret %d\n", ret);
180 		if (ret != len)
181 			return(FAIL);
182 		if ((msglen -= len) <= 0)
183 			break;
184 	}
185 	if (len < 0 || (len == 0 && msglen != 0)) return(FAIL);
186 	return(SUCCESS);
187 }
188 
189 /*
190  * read data from link and
191  * write into file
192  *	fp2	-> file descriptor
193  *	fn	-> link descriptor
194  * returns:
195  *	SUCCESS	-> ok
196  *	FAIL	-> failure on link
197  */
198 int
199 erddata(fn, fp2)
200 FILE *fp2;
201 {
202 	int ret;
203 	int	fd2;
204 	char bufr[EBUFSIZ];
205 	int	len;
206 	long	msglen, bytes;
207 	char	cmsglen[EMESGLEN], *cptr, *erdptr = Erdstash;
208 
209 	DEBUG(9, "erddata wants %d\n", sizeof(cmsglen));
210 	if (Erdlen > 0) {
211 		DEBUG(9, "%d bytes stashed\n", Erdlen);
212 		if (Erdlen >= sizeof(cmsglen)) {
213 			memcpy(cmsglen, erdptr, sizeof(cmsglen));
214 			Erdlen -= sizeof(cmsglen);
215 			erdptr += sizeof(cmsglen);
216 			ret = len = 0;
217 		} else {
218 			memcpy(cmsglen, Erdstash, Erdlen);
219 			cptr = cmsglen + Erdlen;
220 			len = sizeof(cmsglen) - Erdlen;
221 			ret = erdblk(cptr, len, fn);
222 			Erdlen = 0;
223 		}
224 	} else {
225 		len = sizeof(cmsglen);
226 		ret = erdblk(cmsglen, sizeof(cmsglen), fn);
227 	}
228 	if (ret != len)
229 		return(FAIL);
230 	ret = SUCCESS;
231 	sscanf(cmsglen, "%ld", &msglen);
232 	if ( ((msglen-1)/512 +1) > Ulimit )
233 		ret = EFBIG;
234 	DEBUG(7, "erddata file is %ld bytes\n", msglen);
235 	fd2 = fileno( fp2 );
236 
237 	if (Erdlen > 0) {
238 		DEBUG(9, "%d bytes stashed\n", Erdlen);
239 		if (write(fileno(fp2), erdptr, Erdlen) != Erdlen)
240 			return(FAIL);
241 		msglen -= Erdlen;
242 		Erdlen = 0;
243 		DEBUG(7, "erddata remainder is %ld bytes\n", msglen);
244 	}
245 
246 	for (;;) {
247 		len = erdblk(bufr, (int) MIN(msglen, EBUFSIZ), fn);
248 		DEBUG(9, "erdblk ret %d\n", len);
249 		if (len < 0) {
250 			DEBUG(7, "erdblk failed\n%s", "");
251 			return(FAIL);
252 		}
253 
254 		/*
255 		 * handle the case for remote socket close.
256 		 */
257 		if (len == 0) {
258 			ret = errno;
259 			DEBUG(7, "erddata: remote socket closed, errno %d\n",
260 				    ret);
261 			break;
262 		}
263 		bytes += len;
264 		putfilesize(bytes);
265 		if ((msglen -= len) < 0) {
266 			DEBUG(7, "erdblk read too much\n%s", "");
267 			return(FAIL);
268 		}
269 		/* this write is to file -- use write(2), not (*Write) */
270 		if ( ret == SUCCESS && write( fd2, bufr, len ) != len ) {
271 			ret = errno;
272 			DEBUG(7, "erddata: write to file failed, errno %d\n", ret);
273 		}
274 		if (msglen == 0)
275 			break;
276 	}
277 	return(ret);
278 }
279 
280 /*
281  * read block from link
282  * reads are timed
283  *	blk	-> address of buffer
284  *	len	-> size to read
285  *	fn	-> link descriptor
286  * returns:
287  *	FAIL	-> link error timeout on link
288  *	i	-> # of bytes read (must not be 0)
289  */
290 int
291 erdblk(blk, len,  fn)
292 char *blk;
293 {
294 	int i, ret;
295 
296 	if(setjmp(Failbuf)) {
297 		DEBUG(7, "timeout (%d sec)\n", msgtime);
298 		return(FAIL);
299 	}
300 
301 	alarm(msgtime);
302 	for (i = 0; i < len; i += ret) {
303 		DEBUG(9, "erdblk ask %d ", len - i);
304 		if ((ret = (*Read)(fn, blk, (unsigned) len - i)) < 0) {
305 			alarm(0);
306 			DEBUG(7, "erdblk read failed\n%s", "");
307 			return(FAIL);
308 		}
309 		DEBUG(9, "erdblk got %d\n", ret);
310 		if (ret == 0)
311 			break;
312 		blk += ret;
313 	}
314 	alarm(0);
315 	return(i);
316 }
317 
318 struct tbuf {
319 	long t_nbytes;
320 	char t_data[TBUFSIZE];
321 };
322 
323 /*
324  * read message from link
325  *	str	-> message buffer
326  *	fn	-> file descriptor
327  * return
328  *	FAIL	-> read timed out
329  *	SUCCESS	-> ok message in str
330  */
331 int
332 trdmsg(str, fn)
333 char *str;
334 {
335 	return(etrdmsg(str, fn, TPACKSIZE));
336 }
337 
338 /*
339  * write message across link
340  *	type	-> message type
341  *	str	-> message body (ascii string)
342  *	fn	-> link file descriptor
343  * return
344  *	FAIL	-> write failed
345  *	SUCCESS	-> write succeeded
346  */
347 int
348 twrmsg(type, str, fn)
349 char type;
350 char *str;
351 {
352 	return(etwrmsg(type, str, fn, TPACKSIZE));
353 }
354 
355 /*
356  * read data from file fp1 and write on link
357  *	fp1	-> file descriptor
358  *	fn	-> link descriptor
359  * returns:
360  *	FAIL	->failure in link
361  *	SUCCESS	-> ok
362  */
363 int
364 twrdata(fp1, fn)
365 FILE *fp1;
366 int	fn;
367 {
368 	int ret;
369 	int len;
370 	unsigned long bytes;
371 	struct tbuf bufr;
372 	struct stat statbuf;
373 
374 	if (setjmp(Failbuf)) {
375 		DEBUG(7, "twrdata failed\n", 0);
376 		return(FAIL);
377 	}
378 	fstat(fileno(fp1), &statbuf);
379 	bytes = 0L;
380 	while ((len = read(fileno(fp1), bufr.t_data, TBUFSIZE)) > 0) {
381 		bufr.t_nbytes = htonl((long)len);
382 		DEBUG(7, "twrdata writing %d ...", len);
383 		bytes += len;
384 		putfilesize(bytes);
385 		len += sizeof(long);
386 		alarm(msgtime);
387 		ret = (*Write)(fn, (char *)&bufr, (unsigned) len);
388 		alarm(0);
389 		DEBUG(7, "ret %d\n", ret);
390 		if (ret != len)
391 			return(FAIL);
392 		if (len != TBUFSIZE+sizeof(long))
393 			break;
394 	}
395 	bufr.t_nbytes = 0;
396 	alarm(msgtime);
397 	ret = write(fn, (char *)&bufr, sizeof(long));
398 	alarm(0);
399 	if (ret != sizeof(long))
400 		return FAIL;
401 	return(SUCCESS);
402 }
403 
404 /*
405  * read data from link and write into file
406  *	fp2	-> file descriptor
407  *	fn	-> link descriptor
408  * returns:
409  *	SUCCESS	-> ok
410  *	FAIL	-> failure on link
411  */
412 int
413 trddata(fn, fp2)
414 FILE *fp2;
415 {
416 	int len, nread;
417 	long Nbytes;
418 	unsigned long bytes = 0L;
419 	char bufr[TBUFSIZE];
420 
421 	for (;;) {
422 		len = erdblk((char *)&Nbytes, sizeof(Nbytes), fn);
423 		DEBUG(7, "trddata ret %d\n", len);
424 		if (len != sizeof(Nbytes))
425 			return(FAIL);
426 		Nbytes = ntohl(Nbytes);
427 		DEBUG(7,"trddata expecting %ld bytes\n", Nbytes);
428 		nread = Nbytes;
429 		if (nread == 0)
430 			break;
431 		len = erdblk(bufr, nread, fn);
432 		if (len != Nbytes)
433 			return(FAIL);
434 		bytes += len;
435 		putfilesize(bytes);
436 		if (write(fileno(fp2), bufr, len) != len)
437 			return(FAIL);
438 	}
439 	return(SUCCESS);
440 }
441 
442 /*
443  * read message from link
444  *	str	-> message buffer
445  *	fn	-> file descriptor
446  *	i	-> if non-zero, amount to read; o.w., read up to '\0'
447  * return
448  *	FAIL	-> read timed out
449  *	SUCCESS	-> ok message in str
450  *
451  * 'e' is fatally flawed -- in a byte stream world, rdmsg can pick up
452  * the cmsglen on a R request.  if this happens, we stash the excess
453  * where rddata can pick it up.
454  */
455 
456 int
457 etrdmsg(str, fn, i)
458 char *str;
459 int i;
460 {
461 	int len;
462 	int nullterm = 0;
463 	char *null, *argstr;
464 
465 
466 	if (i == 0) {
467 		DEBUG(9, "etrdmsg looking for null terminator\n", 0);
468 		nullterm++;
469 		i = EBUFSIZ;
470 		argstr = str;
471 	}
472 
473 	if(setjmp(Failbuf)) {
474 		DEBUG(7, "timeout (%d sec)\n", msgtime);
475 		return(FAIL);
476 	}
477 
478 	alarm(msgtime);
479 	for (;;) {
480 		DEBUG(9, "etrdmsg want %d ...", i);
481 		len = (*Read)(fn, str, i);
482 		DEBUG(9, "got %d\n", len);
483 		if (len == 0)
484 			continue;	/* timeout will get this */
485 		if (len < 0) {
486 			alarm(0);
487 			return(FAIL);
488 		}
489 		str += len;
490 		i -= len;
491 		if (nullterm) {
492 			/* no way can a msg be as long as EBUFSIZ-1 ... */
493 			*str = 0;
494 			null = strchr(argstr, '\0');
495 			if (null != str) {
496 				null++;	/* start of stash */
497 				memcpy(Erdstash + Erdlen, null, str - null);
498 				Erdlen += str - null;
499 				break;
500 			} else
501 				argstr = str;
502 		} else {
503 			if (i == 0)
504 				break;
505 		}
506 	}
507 	alarm(0);
508 	return(SUCCESS);
509 }
510 
511 /*
512  * write message across link
513  *	type	-> message type
514  *	str	-> message body (ascii string)
515  *	fn	-> link file descriptor
516  *	len	-> if non-zero, amount to write;
517 		   o.w., write up to '\0' (inclusive)
518  * return
519  *	FAIL	-> write failed
520  *	SUCCESS	-> write succeeded
521  */
522 int
523 etwrmsg(type, str, fn, len)
524 char type;
525 char *str;
526 int fn, len;
527 {
528 	char bufr[EBUFSIZ], *endstr;
529 	int ret;
530 
531 	bufr[0] = type;
532 
533 	/* point endstr to last character to be sent */
534 	if ((endstr = strchr(str, '\n')) != 0)
535 		*endstr = 0;
536 	else
537 		endstr = str + strlen(str);
538 
539 	memcpy(bufr+1, str, (endstr - str) + 1);	/* include '\0' */
540 	if (len == 0)
541 		len = (endstr - str) + 2;	/* include bufr[0] and '\0' */
542 	else
543 		bufr[len-1] = 0;		/* 't' needs this terminator */
544 
545 
546 	if (setjmp(Failbuf)) {
547 		DEBUG(7, "etwrmsg write failed\n", 0);
548 		return(FAIL);
549 	}
550 	DEBUG(9, "etwrmsg want %d ... ", len);
551 	alarm(msgtime);
552 	ret = (*Write)(fn, bufr, (unsigned) len);
553 	alarm(0);
554 	DEBUG(9, "sent %d\n", ret);
555 	if (ret != len)
556 		return(FAIL);
557 	return(SUCCESS);
558 }
559 #endif	/* E_PROTOCOL */
560