1 /* Sample system-dependent communications i/o routines for embedded Kermit. */ 2 3 /* 4 Author: Frank da Cruz. 5 Copyright (C) 1995, 2011. 6 Trustees of Columbia University in the City of New York. 7 All rights reserved. 8 See kermit.c for license. 9 */ 10 11 /* 12 The sample i/o routines for UNIX that provide packet i/o 13 functions on the console (login) device. 14 Copy this file, rename it appropriately, and replace the contents 15 of each routine appropriately for your platform. 16 17 Device i/o: 18 19 int devopen() Communications device - open 20 int pktmode() Communications device - enter/exit packet mode 21 int readpkt() Communications device - read a packet 22 int tx_data() Communications device - send data 23 int devclose() Communications device - close 24 int inchk() Communications device - check if bytes are ready to read 25 26 File i/o: 27 28 int openfile() File - open for input or output 29 ULONG fileinfo() Get input file modtime and size 30 int readfile() Input file - read data 31 int writefile() Output file - write data 32 int closefile() Input or output file - close 33 34 Full definitions below, prototypes in kermit.h. 35 36 These routines must handle speed setting, parity, flow control, file i/o, 37 and similar items without the kermit() routine knowing anything about it. 38 If parity is in effect, these routines must add it to outbound characters 39 and strip it from inbound characters. 40 */ 41 #include <stdio.h> 42 #include <sys/stat.h> 43 #include <time.h> 44 #include <errno.h> 45 #ifndef O_WRONLY 46 #include <sys/file.h> 47 #ifdef X_OK 48 #undef X_OK 49 #endif /* X_OK */ 50 #endif /* O_WRONLY */ 51 52 #include "cdefs.h" 53 #include "debug.h" 54 #include "platform.h" 55 #include "kermit.h" 56 57 UCHAR o_buf[OBUFLEN+8]; /* File output buffer */ 58 UCHAR i_buf[IBUFLEN+8]; /* File output buffer */ 59 60 /* 61 In this example, the output file is unbuffered to ensure that every 62 output byte is commited. The input file, however, is buffered for speed. 63 This is just one of many possible implmentation choices, invisible to the 64 Kermit protocol module. 65 */ 66 static int ttyfd, ofile = -1; /* File descriptors */ 67 static FILE * ifile = (FILE *)0; /* and pointers */ 68 69 /* Debugging */ 70 71 #ifdef DEBUG 72 static FILE * dp = (FILE *)0; /* Debug log */ 73 static int xdebug = 0; /* Debugging on/off */ 74 75 void 76 dodebug(int fc, UCHAR * label, UCHAR * sval, long nval) { 77 78 if (fc != DB_OPN && !xdebug) 79 return; 80 if (!label) 81 label = ""; 82 83 switch (fc) { /* Function code */ 84 case DB_OPN: /* Open debug log */ 85 if (dp) fclose(dp); 86 if (!*label) label = "debug.log"; 87 dp = fopen(label,"w"); 88 if (!dp) { 89 dp = stderr; 90 } else { 91 setbuf(dp,(char *)0); 92 } 93 xdebug = 1; 94 fprintf(dp,"DEBUG LOG OPEN\n"); 95 return; 96 case DB_MSG: /* Write a message */ 97 if (dp) fprintf(dp,"%s\n",label); 98 return; 99 case DB_CHR: /* Write label and character */ 100 if (dp) fprintf(dp,"%s=[%c]\n",label,(char)nval); 101 return; 102 case DB_PKT: /* Log a packet */ 103 /* (fill in later, fall thru for now...) */ 104 case DB_LOG: /* Write label and string or number */ 105 if (sval && dp) 106 fprintf(dp,"%s[%s]\n",label,sval); 107 else 108 fprintf(dp,"%s=%ld\n",label,nval); 109 return; 110 case DB_CLS: /* Close debug log */ 111 if (dp) { 112 fclose(dp); 113 dp = (FILE *)0; 114 } 115 xdebug = 0; 116 } 117 } 118 #endif /* DEBUG */ 119 120 /* D E V O P E N -- Open communications device */ 121 /* 122 123 Call with: string pointer to device name. This routine should get the 124 current device settings and save them so devclose() can restore them. 125 It should open the device. If the device is a serial port, devopen() 126 set the speed, stop bits, flow control, etc. 127 Returns: 0 on failure, 1 on success. 128 */ 129 int 130 devopen(char *device) { 131 ttyfd = 0; 132 return(1); 133 } 134 135 /* P K T M O D E -- Put communications device into or out of packet mode */ 136 /* 137 Call with: 0 to put in normal (cooked) mode, 1 to put in packet (raw) mode. 138 For a "dumb i/o device" like an i/o port that does not have a login attached 139 to it, this routine can usually be a no-op. 140 Returns: 0 on failure, 1 on success. 141 */ 142 int 143 pktmode(short on) { 144 if (ttyfd < 0) /* Device must be open */ 145 return(0); 146 system(on ? "stty raw -echo" : "stty sane"); /* Crude but effective */ 147 return(1); 148 } 149 150 151 /* D E V S E T T I N G S */ 152 153 int 154 devsettings(char * s) { 155 /* Get current device settings, save them for devrestore() */ 156 /* Parse string s, do whatever it says, e.g. "9600;8N1" */ 157 if (!pktmode(ON)) /* And put device in packet mode */ 158 return(0); 159 return(1); 160 } 161 162 /* D E V R E S T O R E */ 163 164 int 165 devrestore(void) { 166 /* Put device back as we found it */ 167 pktmode(OFF); 168 return(1); 169 } 170 171 172 /* D E V C L O S E -- Closes the current open communications device */ 173 /* 174 Call with: nothing 175 Closes the device and puts it back the way it was found by devopen(). 176 Returns: 0 on failure, 1 on success. 177 */ 178 int 179 devclose(void) { 180 ttyfd = -1; 181 return(1); 182 } 183 184 /* I N C H K -- Check if input waiting */ 185 186 /* 187 Check if input is waiting to be read, needed for sliding windows. This 188 sample version simply looks in the stdin buffer (which is not portable 189 even among different Unixes). If your platform does not provide a way to 190 look at the device input buffer without blocking and without actually 191 reading from it, make this routine return -1. On success, returns the 192 numbers of characters waiting to be read, i.e. that can be safely read 193 without blocking. 194 */ 195 int 196 inchk(struct k_data * k) { 197 #ifdef _IO_file_flags /* Linux */ 198 if (ttyfd < 0) /* Device must be open */ 199 return(0); 200 return((int) ((stdin->_IO_read_end) - (stdin->_IO_read_ptr))); 201 #else 202 #ifdef AIX /* AIX */ 203 if (ttyfd < 0) 204 return(0); 205 return(stdin->_cnt); 206 #else 207 #ifdef SunOS /* Solaris and SunOS */ 208 if (ttyfd < 0) 209 return(0); 210 return(stdin->_cnt); 211 #else 212 #ifdef HPUX /* HPUX */ 213 if (ttyfd < 0) 214 return(0); 215 return(stdin->__cnt); 216 #else 217 return(-1); 218 #endif /* HPUX */ 219 #endif /* SunOS */ 220 #endif /* AIX */ 221 #endif /* _IO_file_flags */ 222 } 223 224 /* R E A D P K T -- Read a Kermit packet from the communications device */ 225 /* 226 Call with: 227 k - Kermit struct pointer 228 p - pointer to read buffer 229 len - length of read buffer 230 231 When reading a packet, this function looks for start of Kermit packet 232 (k->r_soh), then reads everything between it and the end of the packet 233 (k->r_eom) into the indicated buffer. Returns the number of bytes read, or: 234 0 - timeout or other possibly correctable error; 235 -1 - fatal error, such as loss of connection, or no buffer to read into. 236 */ 237 238 int 239 readpkt(struct k_data * k, UCHAR *p, int len, int fc) { 240 int x, n, max; 241 short flag; 242 UCHAR c; 243 /* 244 Timeout not implemented in this sample. 245 It should not be needed. All non-embedded Kermits that are capable of 246 making connections are also capable of timing out, and only one Kermit 247 needs to time out. NOTE: This simple example waits for SOH and then 248 reads everything up to the negotiated packet terminator. A more robust 249 version might be driven by the value of the packet-length field. 250 */ 251 #ifdef DEBUG 252 char * p2; 253 #endif /* DEBUG */ 254 255 #ifdef F_CTRLC 256 short ccn; 257 ccn = 0; 258 #endif /* F_CTRLC */ 259 260 if (ttyfd < 0 || !p) { /* Device not open or no buffer */ 261 debug(DB_MSG,"readpkt FAIL",0,0); 262 return(-1); 263 } 264 flag = n = 0; /* Init local variables */ 265 266 #ifdef DEBUG 267 p2 = p; 268 #endif /* DEBUG */ 269 270 while (1) { 271 x = getchar(); /* Replace this with real i/o */ 272 c = (k->parity) ? x & 0x7f : x & 0xff; /* Strip parity */ 273 274 #ifdef F_CTRLC 275 /* In remote mode only: three consecutive ^C's to quit */ 276 if (k->remote && c == (UCHAR) 3) { 277 if (++ccn > 2) { 278 debug(DB_MSG,"readpkt ^C^C^C",0,0); 279 return(-1); 280 } 281 } else { 282 ccn = 0; 283 } 284 #endif /* F_CTRLC */ 285 286 if (!flag && c != k->r_soh) /* No start of packet yet */ 287 continue; /* so discard these bytes. */ 288 if (c == k->r_soh) { /* Start of packet */ 289 flag = 1; /* Remember */ 290 continue; /* But discard. */ 291 } else if (c == k->r_eom /* Packet terminator */ 292 || c == '\012' /* 1.3: For HyperTerminal */ 293 ) { 294 #ifdef DEBUG 295 *p = NUL; /* Terminate for printing */ 296 debug(DB_PKT,"RPKT",p2,n); 297 #endif /* DEBUG */ 298 return(n); 299 } else { /* Contents of packet */ 300 if (n++ > k->r_maxlen) /* Check length */ 301 return(0); 302 else 303 *p++ = x & 0xff; 304 } 305 } 306 debug(DB_MSG,"READPKT FAIL (end)",0,0); 307 return(-1); 308 } 309 310 /* T X _ D A T A -- Writes n bytes of data to communication device. */ 311 /* 312 Call with: 313 k = pointer to Kermit struct. 314 p = pointer to data to transmit. 315 n = length. 316 Returns: 317 X_OK on success. 318 X_ERROR on failure to write - i/o error. 319 */ 320 int 321 tx_data(struct k_data * k, UCHAR *p, int n) { 322 int x; 323 int max; 324 325 max = 10; /* Loop breaker */ 326 327 while (n > 0) { /* Keep trying till done */ 328 x = write(ttyfd,p,n); 329 debug(DB_MSG,"tx_data write",0,x); 330 if (x < 0 || --max < 1) /* Errors are fatal */ 331 return(X_ERROR); 332 n -= x; 333 p += x; 334 } 335 return(X_OK); /* Success */ 336 } 337 338 /* O P E N F I L E -- Open output file */ 339 /* 340 Call with: 341 Pointer to filename. 342 Size in bytes. 343 Creation date in format yyyymmdd hh:mm:ss, e.g. 19950208 14:00:00 344 Mode: 1 = read, 2 = create, 3 = append. 345 Returns: 346 X_OK on success. 347 X_ERROR on failure, including rejection based on name, size, or date. 348 */ 349 int 350 openfile(struct k_data * k, UCHAR * s, int mode) { 351 352 switch (mode) { 353 case 1: /* Read */ 354 if (!(ifile = fopen(s,"r"))) { 355 debug(DB_LOG,"openfile read error",s,0); 356 return(X_ERROR); 357 } 358 k->s_first = 1; /* Set up for getkpt */ 359 k->zinbuf[0] = '\0'; /* Initialize buffer */ 360 k->zinptr = k->zinbuf; /* Set up buffer pointer */ 361 k->zincnt = 0; /* and count */ 362 debug(DB_LOG,"openfile read ok",s,0); 363 return(X_OK); 364 365 case 2: /* Write (create) */ 366 ofile = creat(s,0644); 367 if (ofile < 0) { 368 debug(DB_LOG,"openfile write error",s,0); 369 return(X_ERROR); 370 } 371 debug(DB_LOG,"openfile write ok",s,0); 372 return(X_OK); 373 374 #ifdef COMMENT 375 case 3: /* Append (not used) */ 376 ofile = open(s,O_WRONLY|O_APPEND); 377 if (ofile < 0) { 378 debug(DB_LOG,"openfile append error",s,0); 379 return(X_ERROR); 380 } 381 debug(DB_LOG,"openfile append ok",s,0); 382 return(X_OK); 383 #endif /* COMMENT */ 384 385 default: 386 return(X_ERROR); 387 } 388 } 389 390 /* F I L E I N F O -- Get info about existing file */ 391 /* 392 Call with: 393 Pointer to filename 394 Pointer to buffer for date-time string 395 Length of date-time string buffer (must be at least 18 bytes) 396 Pointer to int file type: 397 0: Prevailing type is text. 398 1: Prevailing type is binary. 399 Transfer mode (0 = auto, 1 = manual): 400 0: Figure out whether file is text or binary and return type. 401 1: (nonzero) Don't try to figure out file type. 402 Returns: 403 X_ERROR on failure. 404 0L or greater on success == file length. 405 Date-time string set to yyyymmdd hh:mm:ss modtime of file. 406 If date can't be determined, first byte of buffer is set to NUL. 407 Type set to 0 (text) or 1 (binary) if mode == 0. 408 */ 409 #ifdef F_SCAN 410 #define SCANBUF 1024 411 #define SCANSIZ 49152 412 #endif /* F_SCAN */ 413 414 ULONG 415 fileinfo(struct k_data * k, 416 UCHAR * filename, UCHAR * buf, int buflen, short * type, short mode) { 417 struct stat statbuf; 418 struct tm * timestamp, * localtime(); 419 420 #ifdef F_SCAN 421 FILE * fp; /* File scan pointer */ 422 char inbuf[SCANBUF]; /* and buffer */ 423 #endif /* F_SCAN */ 424 425 if (!buf) 426 return(X_ERROR); 427 buf[0] = '\0'; 428 if (buflen < 18) 429 return(X_ERROR); 430 if (stat(filename,&statbuf) < 0) 431 return(X_ERROR); 432 timestamp = localtime(&(statbuf.st_mtime)); 433 sprintf(buf,"%04d%02d%02d %02d:%02d:%02d", 434 timestamp->tm_year + 1900, 435 timestamp->tm_mon + 1, 436 timestamp->tm_mday, 437 timestamp->tm_hour, 438 timestamp->tm_min, 439 timestamp->tm_sec 440 ); 441 #ifdef F_SCAN 442 /* 443 Here we determine if the file is text or binary if the transfer mode is 444 not forced. This is an extremely crude sample, which diagnoses any file 445 that contains a control character other than HT, LF, FF, or CR as binary. 446 A more thorough content analysis can be done that accounts for various 447 character sets as well as various forms of Unicode (UTF-8, UTF-16, etc). 448 Or the diagnosis could be based wholly or in part on the filename. 449 etc etc. Or the implementation could skip this entirely by not defining 450 F_SCAN and/or by always calling this routine with type set to -1. 451 */ 452 if (!mode) { /* File type determination requested */ 453 int isbinary = 1; 454 fp = fopen(filename,"r"); /* Open the file for scanning */ 455 if (fp) { 456 int n = 0, count = 0; 457 char c, * p; 458 459 debug(DB_LOG,"fileinfo scan ",filename,0); 460 461 isbinary = 0; 462 while (count < SCANSIZ && !isbinary) { /* Scan this much */ 463 n = fread(inbuf,1,SCANBUF,fp); 464 if (n == EOF || n == 0) 465 break; 466 count += n; 467 p = inbuf; 468 while (n--) { 469 c = *p++; 470 if (c < 32 || c == 127) { 471 if (c != 9 && /* Tab */ 472 c != 10 && /* LF */ 473 c != 12 && /* FF */ 474 c != 13) { /* CR */ 475 isbinary = 1; 476 debug(DB_MSG,"fileinfo BINARY",0,0); 477 break; 478 } 479 } 480 } 481 } 482 fclose(fp); 483 *type = isbinary; 484 } 485 } 486 #endif /* F_SCAN */ 487 488 return((ULONG)(statbuf.st_size)); 489 } 490 491 492 /* R E A D F I L E -- Read data from a file */ 493 494 int 495 readfile(struct k_data * k) { 496 if (!k->zinptr) { 497 #ifdef DEBUG 498 fprintf(dp,"readfile ZINPTR NOT SET\n"); 499 #endif /* DEBUG */ 500 return(X_ERROR); 501 } 502 if (k->zincnt < 1) { /* Nothing in buffer - must refill */ 503 if (k->binary) { /* Binary - just read raw buffers */ 504 k->dummy = 0; 505 k->zincnt = fread(k->zinbuf, 1, k->zinlen, ifile); 506 debug(DB_LOG,"readfile binary ok zincnt",0,k->zincnt); 507 508 } else { /* Text mode needs LF/CRLF handling */ 509 int c; /* Current character */ 510 for (k->zincnt = 0; (k->zincnt < (k->zinlen - 2)); (k->zincnt)++) { 511 if ((c = getc(ifile)) == EOF) 512 break; 513 if (c == '\n') /* Have newline? */ 514 k->zinbuf[(k->zincnt)++] = '\r'; /* Insert CR */ 515 k->zinbuf[k->zincnt] = c; 516 } 517 #ifdef DEBUG 518 k->zinbuf[k->zincnt] = '\0'; 519 debug(DB_LOG,"readfile text ok zincnt",0,k->zincnt); 520 #endif /* DEBUG */ 521 } 522 k->zinbuf[k->zincnt] = '\0'; /* Terminate. */ 523 if (k->zincnt == 0) /* Check for EOF */ 524 return(-1); 525 k->zinptr = k->zinbuf; /* Not EOF - reset pointer */ 526 } 527 (k->zincnt)--; /* Return first byte. */ 528 529 debug(DB_LOG,"readfile exit zincnt",0,k->zincnt); 530 debug(DB_LOG,"readfile exit zinptr",0,k->zinptr); 531 return(*(k->zinptr)++ & 0xff); 532 } 533 534 535 /* W R I T E F I L E -- Write data to file */ 536 /* 537 Call with: 538 Kermit struct 539 String pointer 540 Length 541 Returns: 542 X_OK on success 543 X_ERROR on failure, such as i/o error, space used up, etc 544 */ 545 int 546 writefile(struct k_data * k, UCHAR * s, int n) { 547 int rc; 548 rc = X_OK; 549 550 debug(DB_LOG,"writefile binary",0,k->binary); 551 552 if (k->binary) { /* Binary mode, just write it */ 553 if (write(ofile,s,n) != n) 554 rc = X_ERROR; 555 } else { /* Text mode, skip CRs */ 556 UCHAR * p, * q; 557 int i; 558 q = s; 559 560 while (1) { 561 for (p = q, i = 0; ((*p) && (*p != (UCHAR)13)); p++, i++) ; 562 if (i > 0) 563 if (write(ofile,q,i) != i) 564 rc = X_ERROR; 565 if (!*p) break; 566 q = p+1; 567 } 568 } 569 return(rc); 570 } 571 572 /* C L O S E F I L E -- Close output file */ 573 /* 574 Mode = 1 for input file, mode = 2 or 3 for output file. 575 576 For output files, the character c is the character (if any) from the Z 577 packet data field. If it is D, it means the file transfer was canceled 578 in midstream by the sender, and the file is therefore incomplete. This 579 routine should check for that and decide what to do. It should be 580 harmless to call this routine for a file that that is not open. 581 */ 582 int 583 closefile(struct k_data * k, UCHAR c, int mode) { 584 int rc = X_OK; /* Return code */ 585 586 switch (mode) { 587 case 1: /* Closing input file */ 588 if (!ifile) /* If not not open */ 589 break; /* do nothing but succeed */ 590 debug(DB_LOG,"closefile (input)",k->filename,0); 591 if (fclose(ifile) < 0) 592 rc = X_ERROR; 593 break; 594 case 2: /* Closing output file */ 595 case 3: 596 if (ofile < 0) /* If not open */ 597 break; /* do nothing but succeed */ 598 debug(DB_LOG,"closefile (output) name",k->filename,0); 599 debug(DB_LOG,"closefile (output) keep",0,k->ikeep); 600 if (close(ofile) < 0) { /* Try to close */ 601 rc = X_ERROR; 602 } else if ((k->ikeep == 0) && /* Don't keep incomplete files */ 603 (c == 'D')) { /* This file was incomplete */ 604 if (k->filename) { 605 debug(DB_LOG,"deleting incomplete",k->filename,0); 606 unlink(k->filename); /* Delete it. */ 607 } 608 } 609 break; 610 default: 611 rc = X_ERROR; 612 } 613 return(rc); 614 } 615 616 #ifdef DEBUG 617 int xerror() { 618 unsigned int x; 619 extern int errorrate; /* Fix this - NO EXTERNS */ 620 if (!errorrate) 621 return(0); 622 x = rand() % 100; /* Fix this - NO C LIBRARY */ 623 debug(DB_LOG,"RANDOM",0,x); 624 debug(DB_LOG,"ERROR",0,(x < errorrate)); 625 return(x < errorrate); 626 } 627 #endif /* DEBUG */ 628