File: rcxtty.c

package info (click to toggle)
lnpd 0.9.0-11
  • links: PTS
  • area: main
  • in suites: bookworm, bullseye, buster, jessie, jessie-kfreebsd, sid, stretch, trixie
  • size: 1,704 kB
  • ctags: 491
  • sloc: sh: 7,947; ansic: 2,543; makefile: 53
file content (189 lines) | stat: -rw-r--r-- 4,661 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/*
 *  The Original Code is legOS code, released October 2, 1999.
 *
 *  The Initial Developer of the Original Code is Markus L. Noga.
 *  Portions created by Markus L. Noga are Copyright (C) 1999
 *  Markus L. Noga. All Rights Reserved.
 *
 *  Contributor(s): Kekoa Proudfoot  <kekoa@graphics.stanford.edu>
 */

#include <stdlib.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#ifdef __linux__
#include <linux/serial.h>
#endif
#include <sys/ioctl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>

#include "logger.h"
#include "lnp.h"
#include "rcxtty.h"

static int fd;
static char *lockfilename;

// try to create lockfile
// returns -1 on failure, 0 on success
static int make_lockfile(const char *device)
{
	char lockname[FILENAME_MAX];
	int nchars,result,lockfd,lockpid;
	FILE* lockfp;
    char filepid[16];
	
	// create lockfile name
    if ( strchr( device, '/' ) != NULL )
        device = strrchr( device, '/' ) +1;
    nchars = snprintf( lockname, FILENAME_MAX, "%s/%s%s" , LOCKDIR, LOCKNAME, device);
    // should work with glibc2.0 and 2.1
    if (nchars < 0 || nchars >= FILENAME_MAX)
    {
    	log(LNPD_LOG_INFO,"tty name too long");
    	return -1;
    }
	
	// create lockfile
	while ( ( lockfd = open(lockname, O_WRONLY | O_CREAT | O_EXCL, 0644) ) < 0 )
	{
	    if (errno != EEXIST )
		{
			log(LNPD_LOG_INFO,"cannot create lockfile: %s", strerror(errno));
 			return -1;
		}
		
		else // lock file already there
		{
			// read pid from Lockfile
			if ( ( lockfp = fopen(lockname, "r" )) == NULL )
			{
				if ( errno == ENOENT ) continue; // lock file disappeared
				else
				{
					log(LNPD_LOG_INFO,"cannot open lockfile %s",lockname);
					return -1;
				}
			}
			result = fscanf(lockfp, "%d", &lockpid);
			fclose( lockfp );
			
			if (result != 1)
			{
				log(LNPD_LOG_INFO,"cannot read pid from lockfile %s",lockname);
				return -1;
			}
			
	    	// check if process already dead or its our own pid
	    	result = kill(lockpid, 0);
	    	if ( (result < 0 && errno == ESRCH) || ( lockpid == (int)getpid() ) )
		    {
				// process is gone, try to remove stale lock
				log( LNPD_LOG_INFO, "trying to unlink stale lockfile");
				if ( unlink(lockname) < 0 &&
			         errno != EINTR && errno != ENOENT )
				{
			    	log( LNPD_LOG_INFO, "cannot unlink stale lockfile: %s",strerror(errno));
			    	return -1;
				}
				continue;
		    }
		
		    log(LNPD_LOG_INFO, "device is locked by pid %d ",lockpid);
			return -1;
		}
	}
	
	lockfilename = strdup(lockname);
	
	// write pid to lockfile
    sprintf( filepid, "%10d\n", (int) getpid() );
    if ( write(lockfd, filepid, strlen(filepid)) != strlen(filepid) )
	{
		log(LNPD_LOG_INFO,"cannot write to lockfile %s",strerror(errno));
    	close(lockfd);
 		return -1;
	}

    close(lockfd);
	log(LNPD_LOG_INFO, "created lock file %s",lockname);
	return 0;
}

void tty_exit(void)
{
	if (lockfilename) unlink(lockfilename);
}	

// initialize RCX communications port
int tty_init(int highspeed,int nolock,const char *device)
{
	struct termios ios;
#ifdef __linux__
    struct serial_struct ttyinfo;
#endif

    // try to create lockfile
    if ( !nolock && make_lockfile(device))
   	{
   		log(LNPD_LOG_FATAL,"cannot create lockfile");
   		exit(1);
	}    	

	// open the device
	if ( (fd = open(device, O_RDWR )) < 0)
 		error_exit("open");

	// check if its a tty
	if (!isatty(fd))
	{
    	log(LNPD_LOG_FATAL, "%s is not a tty", device);
    	exit(1);
	}
	
	// set to noncanonical mode, implies nonblocking behaviour
	memset(&ios, 0, sizeof(ios));
  	ios.c_cflag = CREAD | CLOCAL | CS8 | (highspeed ? 0 : PARENB | PARODD);
	cfsetispeed(&ios, highspeed ? LNP_BAUD_FAST : LNP_BAUD_SLOW );
	cfsetospeed(&ios, highspeed ? LNP_BAUD_FAST : LNP_BAUD_SLOW );
  	if (tcsetattr(fd, TCSANOW, &ios) == -1)
    	error_exit("tcsetattr");
    	
#ifdef __linux__
	// try to set to "hard realtime mode"
    if  (ioctl(fd,TIOCGSERIAL,&ttyinfo))
    	error_exit("ioctl[TIOCGSERIAL]");
    	
    switch (ttyinfo.type)
    {
	   	case PORT_16550A:
			ttyinfo.type = PORT_16450;
    		ttyinfo.flags |= ASYNC_LOW_LATENCY;
	   		break;
	   	case PORT_16450:
    	case PORT_8250:
    	case PORT_16550:
    		ttyinfo.flags |= ASYNC_LOW_LATENCY;
    		break;
	   	default:
  			log(LNPD_LOG_INFO,"dont know how to configure tty, trying low_latency");
    		ttyinfo.flags |= ASYNC_LOW_LATENCY;
    }
	
	if (ioctl(fd,TIOCSSERIAL,&ttyinfo))
	{
		log(LNPD_LOG_INFO,"failed to configure tty: %s",strerror(errno));
	}
#endif
	
	// we must close and reopen the tty
	close(fd);
	if ( (fd = open(device, O_RDWR )) < 0)
 		error_exit("open");
	
    return fd;
}