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