//
// Program for loging input on a serial port
//
// Copyright (c) 1998,2000 Sinkovics Zoltan
//
// Released under the conditions of the GNU General
// Public License.
//
#include "logserial.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
//*#include <lockdev.h>
#define MAXPATH 255
char NAME[MAXPATH]; // program name
int outfd; // output file descriptor
int infd; // input file descriptor
int portfd; // serial port file descriptor
int pipefd; // named pipe file descriptor
//*char myTTY[MAXPATH]; // tty device name as a global variable
void closetty(int sig) ;
void version(void) ;
void usage(void) ;
void version(void)
{
fprintf(stdout,"
%s-%s by Sinkovics Zoltan
",NAME,VERSION);
}
void usage(void)
{
fprintf(stderr,"
%s-%s
",NAME,VERSION);
fprintf(stderr," usage: %s [parameters]
",NAME);
fprintf(stderr," Optional parameters are:
");
fprintf(stderr," -h prints this help screen
");
fprintf(stderr," -v prints version of %s
",NAME);
fprintf(stderr," -t tty default /dev/ttyS1
");
fprintf(stderr," -s speed default 9600
");
fprintf(stderr," -d data bits default 8
");
fprintf(stderr," -p parity default N
");
fprintf(stderr," -c if exists software handshake used (by default hw used)
");
fprintf(stderr," -f output file default /dev/stdout
");
fprintf(stderr," -b if exists logserial run as a daemon
");
fprintf(stderr," -r if exists logserial run in reverse mode
");
fprintf(stderr," -n filename specify input named pipe in reverse mode
");
fprintf(stderr," -a use this option if you will read output file wit DOS
");
fprintf(stderr," -u umask specify umask for logserial
");
fprintf(stderr," -m mask specify file creation mode for logserial
");
}
int main(int argc, char **argv)
{
int c,childproc;
char tty[MAXPATH]; // serial port tty
char baudrate[10]; // baud rate as a string
char parity[10]; // parity as a string
char bits[10]; // data bits as a string
int hwhandshake=1; // true if RTS/CTS handshake used
int swhandshake=0; // true if XON/XOFF handshake used
char fileout[MAXPATH]; // output file
char filein[MAXPATH]; // input file
char filepipe[MAXPATH]; // name of the named pipe
struct stat filestatus; // status of the output file
int daemonize=0; // true if daemonize is enabled
int reverse=0; // true if reverse mode selected
int named_pipe=0; // true if name pipe mode used
int dos_converter=0; // true if dos converter mode is active
int n; // just for the for
mode_t um=0; // default umask
mode_t rwxmode ; // read,write,execute rights
fd_set fds; // file descriptor set for reading
fd_set fds_out; // file descriptor set for writing
struct timeval tv; // struct for time interval for select
int buflen ; // length of buffer
char buf[128] ; // input character buffer
FILE* input_stream=NULL ; // input file descriptor as a stream
//* pid_t dev_locked; // tty lockfile flag
strcpy(fileout , "/dev/stdout" );
strcpy(filein , "/dev/stdin" );
strcpy(filepipe , "/tmp/trypipe");
strcpy(bits , "8" );
strcpy(parity , "N" );
strcpy(baudrate , "9600" );
strcpy(tty , "/dev/ttyS1" );
strcpy(NAME , "logserial" );
rwxmode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH ;
/* parse command line */
while ((c = getopt (argc, argv, "t:s:d:p:f:cvhbrn:au:m:")) != EOF)
{
switch (c)
{
case 'h': // help
usage();
exit(EXIT_SUCCESS);
break;
case 'v': // version
version();
exit(EXIT_SUCCESS);
break;
case 't': // tty
if (strlen(optarg) > (MAXPATH-1))
{
fprintf(stderr,"Too long tty path arg!!
");
exit(EXIT_FAILURE);
}
strcpy(tty, optarg);
break;
case 's': // speed
if (strlen(optarg)>9)
{
fprintf(stderr,"Too long baudrate arg!!
");
exit(EXIT_FAILURE);
}
strcpy (baudrate, optarg);
break;
case 'd': // data
if (strlen(optarg)>9)
{
fprintf(stderr,"Too long bit number arg!!
");
exit(EXIT_FAILURE);
}
strcpy (bits, optarg);
break;
case 'p': // parity
if (strlen(optarg)>9)
{
fprintf(stderr,"Too long parity arg!!
");
exit(EXIT_FAILURE);
}
strcpy (parity, optarg);
break;
case 'c': // flow control (handshake)
swhandshake=1;
hwhandshake=0;
break;
case 'f': // output file
if (strlen(optarg)>(MAXPATH-1))
{
fprintf(stderr,"Too long output file arg!!
");
exit(EXIT_FAILURE);
}
strcpy(fileout, optarg);
break;
case 'b':
daemonize=1;
break;
case 'r':
reverse=1;
break;
case 'n':
if (strlen(optarg) > (MAXPATH-1))
{
fprintf(stderr,"Too long named pipe path arg!!
");
exit(EXIT_FAILURE);
}
strcpy(filepipe, optarg);
named_pipe=1;
reverse=1;
break;
case 'a':
dos_converter=1;
break;
case 'u':
sscanf(optarg,"%o",&um) ;
umask(um) ;
break ;
case 'm':
sscanf(optarg,"%o",&rwxmode) ;
break ;
}
}
// daemonize now if requested...
if(daemonize==1) {
childproc=fork();
if(childproc==-1) {
perror("Unable to fork");
exit(EXIT_FAILURE);
}
if(childproc!=0) {
fprintf(stderr,"Started logserial daemon...
");
exit(EXIT_SUCCESS);
}
}
if(named_pipe)
{
// unlink(filepipe);
//umask(0);
pipefd = mknod(filepipe, S_IFIFO|rwxmode, 0);
if ( pipefd != -1 )
{
fprintf(stderr,"%s created successfully.",filepipe);
}
else
{
if ((pipefd == -1) && (errno == EEXIST))
{
fprintf(stderr,"%s already exists. Will use it.
",filepipe);
}
else
{
fprintf(stderr,"Error creating %s. Exiting.
",filepipe);
exit(EXIT_FAILURE);
}
}
}
if (!reverse)
{
// makes new file if logfile not exists, if exists append log to it
outfd = open(fileout,O_WRONLY|O_CREAT|O_APPEND,rwxmode);
if (outfd == -1)
{
fprintf(stderr,"Can't open %s for writing.
",fileout);
exit(EXIT_FAILURE);
}
}
else
{
if (named_pipe)
{
strcpy(filein,filepipe);
}
infd = open(filein, O_RDONLY);
if (infd == -1)
{
fprintf(stderr,"Can't open %s for reading.
",fileout);
exit(EXIT_FAILURE);
}
if (!named_pipe)
{
input_stream = fdopen(infd,"r");
}
}
//* // Let's see if the serial port is locked
//* dev_locked = dev_lock( tty ) ;
//*
//* if (dev_locked > 0) {
//* fprintf(stderr,"Can't get a lock on %s. Process # %d has it locked
",tty ,dev_locked) ;
//* close(outfd) ;
//* exit(EXIT_FAILURE) ;
//* }
//* else if (dev_locked < 0) {
//* fprintf(stderr,"Can't get a lock on %s. Unknown error. Sorry!
",tty) ;
//* close(outfd) ;
//* exit(EXIT_FAILURE) ;
//* }
//* else {
//* // There is program locking this tty already.
//* // Let's try opening the tty.
portfd = open(tty,O_RDWR);
if (portfd == -1)
{
fprintf(stderr,"Can't open %s .
",tty);
close(outfd);
exit(EXIT_FAILURE);
}
//* }
m_savestate(portfd);
m_setparms(portfd,baudrate,parity,bits,hwhandshake,swhandshake);
m_nohang(portfd);
m_hupcl(portfd,1);
m_flush(portfd);
//* // Stow our tty name in a global variable
//* // so we can remove the lock when the program exits.
//* strcpy(myTTY, tty) ;
signal (SIGHUP, &closetty);
signal (SIGINT, &closetty);
signal (SIGQUIT, &closetty);
signal (SIGTERM, &closetty);
signal (SIGABRT, &closetty);
if (!reverse)
fprintf(stderr,"Successfully opened %s. Start loging.
",tty);
else
fprintf(stderr,"Successfully opened %s. Start sending.
",tty);
while(1)
{
if (!reverse)
{
tv.tv_sec=1 ; // 1 second
tv.tv_usec=0 ;
FD_ZERO(&fds );
FD_SET(portfd, &fds);
if (select(portfd+1, &fds, NULL, NULL, &tv) > 0)
{
buflen = read(portfd, buf, 127);
if (buflen == -1) closetty(-1);
if (buflen > 0 ) // got input bytes
{
if (stat(fileout , &filestatus)==-1) // This makes a new file if the logfile was deleted.
{
outfd = open(fileout,O_WRONLY|O_CREAT,rwxmode);
if (outfd == -1)
{
fprintf(stderr,"Output file was deleted, can't create new %s for writing.
",fileout);
close(portfd);
exit(EXIT_FAILURE);
}
}
if (!dos_converter)
{
if (write(outfd, buf, buflen) != buflen) closetty(-2) ; // and put it onto output
}
else
for(n=0;n < buflen;n++)
{
write(outfd, buf+n, 1);
if (buf[n] == 0x0d)
{
buf[n] = 0x0a ;
write(outfd, buf+n, 1) ;
}
}
fsync(outfd);
}
}
}
else
{
if (named_pipe)
{
tv.tv_sec=1 ; // 1 second
tv.tv_usec=0 ;
FD_ZERO(&fds );
FD_SET(infd, &fds);
FD_ZERO(&fds_out );
FD_SET(portfd, &fds_out);
if (select(portfd+1, &fds, &fds_out, NULL, &tv) > 0)
{
if ( !FD_ISSET(infd, &fds))
{
continue;
}
if (!FD_ISSET(portfd, &fds_out))
{
continue;
}
buflen = read(infd, buf,

;
if (buflen == -1) closetty(-3);
if (buflen > 0 ) // got input bytes
{
if (write(portfd, buf, buflen) != buflen) closetty(-4) ; // and put it onto output
fsync(outfd);
}
}
}
else
{
tv.tv_sec=1 ; // 1 second
tv.tv_usec=0 ;
FD_ZERO(&fds );
FD_SET(infd, &fds);
FD_ZERO(&fds_out );
FD_SET(portfd, &fds_out);
if (select(portfd+1, &fds, &fds_out, NULL, &tv) > 0)
{
if ( !FD_ISSET(infd, &fds))
{
continue;
}
if (!FD_ISSET(portfd, &fds_out))
{
continue;
}
buflen = read(infd, buf,

;
if (buflen == -1) closetty(-3);
if (buflen > 0 ) // got input bytes
{
if (write(portfd, buf, buflen) != buflen) closetty(-4) ; // and put it onto output
fsync(outfd);
}
if (buflen==0)
{
fprintf(stderr,"No more input. Exiting
");
exit(EXIT_SUCCESS);
}
}
}
}
}
return(0);
}
void closetty(int sig)
{
//* pid_t temp_lock ;
switch (sig) {
case -1:
fprintf(stderr,"Read error on tty. Closing communication port
");
break;
case -2:
fprintf(stderr,"Write error on output. Closing communication port
");
break;
case -3:
fprintf(stderr,"Read error on input file. Closing communication port
");
break;
case -4:
fprintf(stderr,"Write error on tty. Closing communication port
");
break;
default:
fprintf(stderr,"Got signal %d. Closing communication port
",sig);
break;
}
//* temp_lock = dev_unlock( myTTY, getpid() );
m_restorestate(portfd);
close(portfd);
close(outfd);
close(infd);
close(pipefd);
exit(EXIT_SUCCESS);
}