Skip to content

Commit e2bb1e2

Browse files
author
Élie Bouttier
committedOct 10, 2012
First commit
0 parents  commit e2bb1e2

15 files changed

+1266
-0
lines changed
 

‎CMakeLists.txt

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
cmake_minimum_required(VERSION 2.6.0)
2+
3+
add_executable(usbdaemon usbdaemon.c settings.c ini.c devicemanager.c device.c
4+
getttyfd.c getsockfd.c notice.c)
5+
6+
target_link_libraries(usbdaemon checktype)
7+
8+
install(TARGETS usbdaemon RUNTIME DESTINATION bin)

‎device.c

+169
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
#include <stdlib.h>
2+
#include <stdio.h>
3+
#include <string.h>
4+
5+
#include "device.h"
6+
#include "settings.h"
7+
#include "notice.h"
8+
9+
int getttyfd(const char *device, int speed);
10+
int getsockfd(const char *host, const char *port);
11+
int checktype(int type);
12+
13+
char format[256];
14+
15+
int device_new(struct device **device, const char *path)
16+
{
17+
struct device *dev = *device;
18+
if ((dev = malloc(sizeof(struct device))) == NULL) {
19+
perror("malloc");
20+
return -1;
21+
}
22+
if ((dev->fd = getttyfd(path, speed)) < 0) {
23+
free(dev);
24+
return -1;
25+
}
26+
dev->fbufsize = 0;
27+
28+
dev->sock = -1;
29+
sprintf(dev->sbuf, "%c%c%c", 129, 254, 128);
30+
dev->sbufsize = 3;
31+
32+
dev->state = BEGIN;
33+
34+
if ((dev->path = malloc(strlen(path) + 1)) == NULL) {
35+
perror("malloc");
36+
close(dev->fd);
37+
free(dev);
38+
return -1;
39+
}
40+
strcpy(dev->path, path);
41+
42+
*device = dev;
43+
return 0;
44+
}
45+
46+
int device_connect(struct device *dev)
47+
{
48+
int i, port;
49+
char service[128];
50+
51+
for (i = 0 ; i < dev->fbufsize ; i++) {
52+
if (dev->state == WAITING_CONNECTION) {
53+
break;
54+
}
55+
switch (dev->state) {
56+
case BEGIN:
57+
if (dev->fbuf[i] == 129) {
58+
dev->state = PACKET_ID;
59+
}
60+
break;
61+
case PACKET_ID:
62+
if (dev->fbuf[i] == 255) {
63+
dev->state = VAR_B;
64+
} else {
65+
dev->state = TYPE;
66+
}
67+
break;
68+
case TYPE:
69+
if (dev->fbuf[i] == 128) {
70+
dev->state = BEGIN;
71+
} else if (checktype(dev->fbuf[i])) {
72+
dev->state = -(dev->fbuf[i] & 0xF);
73+
} else {
74+
dev->state = BEGIN;
75+
}
76+
break;
77+
case VAR_B:
78+
if (dev->fbuf[i] == 0x1) {
79+
dev->state = DEV_ID;
80+
} else {
81+
dev->state = BEGIN;
82+
}
83+
break;
84+
case DEV_ID:
85+
dev->sock = dev->fbuf[i];
86+
dev->state = END;
87+
break;
88+
case END:
89+
if (dev->fbuf[i] == 128) {
90+
dev->state = WAITING_CONNECTION;
91+
} else if (checktype(dev->fbuf[i])) {
92+
dev->state = -(dev->fbuf[i] & 0xF);
93+
} else {
94+
dev->state = BEGIN;
95+
}
96+
break;
97+
default:
98+
dev->state += 1;
99+
}
100+
}
101+
102+
memmove(dev->fbuf, dev->fbuf + i, (dev->fbufsize - i) * sizeof(*(dev->fbuf)));
103+
dev->fbufsize -= i;
104+
105+
if (dev->state != WAITING_CONNECTION)
106+
return 0;
107+
108+
if (!(port = getportbyid(dev->sock))) {
109+
fprintf(stderr, "getportbyid: no port associated with this id (%d)\n", dev->sock);
110+
//notice_id(IDFAIL, dev->path, dev->sock);
111+
return -1;
112+
}
113+
114+
sprintf(service, "%d", port);
115+
116+
if ((dev->sock = getsockfd(host, service)) < 0) {
117+
notice_sock(SOCKFAIL, dev->path, host, service);
118+
return -1;
119+
}
120+
121+
dev->state = CONNECTED;
122+
notice_sock(CONNECT, dev->path, host, service);
123+
124+
return 0;
125+
}
126+
127+
128+
int device_read(int fd, unsigned char *buffer, int *bufsize)
129+
{
130+
int readed;
131+
132+
if ((readed = read(fd, buffer + *bufsize, BUF_SIZE - *bufsize)) <= 0) {
133+
return -1;
134+
}
135+
*bufsize += readed;
136+
137+
return 0;
138+
}
139+
140+
int device_write(int fd, unsigned char *buffer, int *bufsize)
141+
{
142+
int written;
143+
144+
if ((written = write(fd, buffer, *bufsize)) <= 0) {
145+
return -1;
146+
}
147+
148+
memmove(buffer, buffer + written, (*bufsize - written) * sizeof(*buffer));
149+
*bufsize -= written;
150+
151+
return 0;
152+
}
153+
154+
void device_delete(struct device **device)
155+
{
156+
struct device *dev = *device;
157+
158+
// Fermeture des fd
159+
close(dev->fd);
160+
if (dev->state == CONNECTED) {
161+
close(dev->sock);
162+
}
163+
164+
// Libération des ressources alloué dans device_new
165+
free(dev->path);
166+
free(dev);
167+
168+
*device = NULL;
169+
}

‎device.h

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#ifndef _DEVICE_H_
2+
#define _DEVICE_H_
3+
4+
#define BUF_SIZE 1024
5+
6+
enum state {
7+
TYPE = 0,
8+
BEGIN = 1,
9+
PACKET_ID = 3,
10+
VAR_TYPE = 4,
11+
VAR_B = 5,
12+
DEV_ID = 6,
13+
END = 7,
14+
WAITING_CONNECTION = 8,
15+
CONNECTED = 9,
16+
};
17+
18+
struct device {
19+
int fd;
20+
unsigned char fbuf[BUF_SIZE];
21+
int fbufsize;
22+
int sock;
23+
unsigned char sbuf[BUF_SIZE];
24+
int sbufsize;
25+
enum state state;
26+
char *path;
27+
};
28+
29+
int device_new(struct device **device, const char *path);
30+
int device_connect(struct device *dev);
31+
int device_read(int fd, unsigned char *buffer, int *bufsize);
32+
int device_write(int fd, unsigned char *buffer, int *bufsize);
33+
void device_delete(struct device **device);
34+
35+
#endif // _DEVICE_H_

‎devicemanager.c

+219
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <unistd.h>
4+
#include <string.h>
5+
#include <signal.h>
6+
#include <sys/time.h>
7+
8+
#include "devicemanager.h"
9+
#include "device.h"
10+
#include "notice.h"
11+
12+
#define MAX_DEVICES 32
13+
#define TIMER 500000
14+
15+
static int *delay;
16+
static char **path;
17+
static int pathc = 0;
18+
static int paths = 0;
19+
static int next = -1;
20+
21+
static struct device *devices[MAX_DEVICES];
22+
static int devc = 0;
23+
24+
static void install_handler();
25+
static void set_timer(int delay);
26+
static void handler(int signal);
27+
28+
static void set_timer(int delay)
29+
{
30+
struct itimerval timer;
31+
next = delay;
32+
timer.it_value.tv_sec = next / 1000000;
33+
timer.it_value.tv_usec = next % 1000000;
34+
timer.it_interval.tv_sec = 0;
35+
timer.it_interval.tv_usec = 0;
36+
if (setitimer(ITIMER_REAL, &timer, NULL) < 0) {
37+
perror("setitimer");
38+
exit(EXIT_FAILURE); // FIXME
39+
}
40+
}
41+
42+
static void install_handler()
43+
{
44+
struct sigaction sa;
45+
memset(&sa, 0, sizeof(sa));
46+
sa.sa_handler = &handler;
47+
sigemptyset(&sa.sa_mask);
48+
sa.sa_flags = SA_RESTART;
49+
if (sigaction(SIGALRM, &sa, NULL) < 0) {
50+
perror("sigaction");
51+
exit(EXIT_FAILURE); // FIXME
52+
}
53+
}
54+
55+
static void handler(int signal)
56+
{
57+
int i, t;
58+
int min = TIMER;
59+
60+
for (i = 0 ; i < pathc ; i++) {
61+
delay[i] -= next;
62+
if (delay[i] <= 0) {
63+
dm_add(path[i]);
64+
free(path[i]);
65+
memmove(path+i, path+i+1, (pathc-i-1) * sizeof(*path));
66+
memmove(delay+i, delay+i+1, (pathc-i-1) * sizeof(*delay));
67+
pathc--;
68+
i--;
69+
} else {
70+
if (delay[i] < min)
71+
min = delay[i];
72+
}
73+
}
74+
75+
if (min < TIMER) {
76+
set_timer(min);
77+
}
78+
}
79+
80+
void dm_scheduledadd(const char *device)
81+
{
82+
int i, t;
83+
int min = TIMER;
84+
static int handler = 0;
85+
struct itimerval timer;
86+
sigset_t sigset_old, sigset_mask;
87+
88+
if (!handler) {
89+
install_handler();
90+
}
91+
92+
sigemptyset(&sigset_mask);
93+
sigaddset(&sigset_mask, SIGALRM);
94+
sigprocmask(SIG_BLOCK, &sigset_mask, &sigset_old);
95+
96+
for (i = 0 ; i < pathc ; i++) {
97+
if (!strcmp(device, path[i])) {
98+
if (getitimer(ITIMER_REAL, &timer) < 0) {
99+
perror("getitimer");
100+
exit(EXIT_FAILURE); // FIXME
101+
}
102+
t = timer.it_value.tv_usec + 1000000 * timer.it_value.tv_sec;
103+
delay[i] = TIMER + next - t;
104+
return;
105+
}
106+
}
107+
108+
notice(NEW, device);
109+
110+
if (pathc == paths) {
111+
paths += 5;
112+
if ((delay = realloc(delay, paths * sizeof(int))) == NULL) {
113+
perror("realloc");
114+
exit(EXIT_FAILURE);
115+
}
116+
if ((path = realloc(path, paths * sizeof(char*))) == NULL) {
117+
perror("realloc");
118+
exit(EXIT_FAILURE);
119+
}
120+
}
121+
if ((path[pathc] = malloc(strlen(device) * sizeof(char) + 1)) == NULL) {
122+
perror("malloc");
123+
exit(EXIT_FAILURE);
124+
}
125+
strcpy(path[pathc], device);
126+
delay[pathc] = TIMER;
127+
pathc++;
128+
129+
if (pathc == 1) {
130+
set_timer(TIMER);
131+
}
132+
133+
sigprocmask(SIG_SETMASK, &sigset_old, NULL);
134+
}
135+
136+
void dm_add(const char *path)
137+
{
138+
if (devc == MAX_DEVICES) {
139+
fprintf(stderr, "%s: too many device\n", __FUNCTION__);
140+
notice(ADDFAIL, path);
141+
return;
142+
}
143+
144+
if (device_new(devices+devc, path) < 0) {
145+
notice(ADDFAIL, path);
146+
return;
147+
}
148+
149+
notice(ADD, path);
150+
151+
devc++;
152+
}
153+
154+
void dm_select(fd_set *readfds, fd_set *writefds)
155+
{
156+
int i;
157+
for (i = 0 ; i < devc ; i++) {
158+
struct device *dev = devices[i];
159+
if (BUF_SIZE - dev->fbufsize > 0) {
160+
FD_SET(dev->fd, readfds);
161+
}
162+
if (BUF_SIZE - dev->sbufsize > 0 && dev->state == CONNECTED) {
163+
FD_SET(dev->sock, readfds);
164+
}
165+
if (dev->sbufsize > 0) {
166+
FD_SET(dev->fd, writefds);
167+
}
168+
if (dev->fbufsize > 0 && dev->state == CONNECTED) {
169+
FD_SET(dev->sock, writefds);
170+
}
171+
}
172+
}
173+
174+
void dm_event(fd_set *readfds, fd_set *writefds)
175+
{
176+
int i = 0;
177+
178+
while (i < devc) {
179+
struct device *dev = devices[i];
180+
if (FD_ISSET(dev->fd, readfds)) {
181+
if (device_read(dev->fd, dev->fbuf, &(dev->fbufsize)) < 0) {
182+
dm_del(i);
183+
continue;
184+
}
185+
if (dev->state != CONNECTED) {
186+
if (device_connect(dev) < 0) {
187+
dm_del(i);
188+
continue;
189+
}
190+
}
191+
}
192+
if (dev->state == CONNECTED && FD_ISSET(dev->sock, readfds)) {
193+
if (device_read(dev->sock, dev->sbuf, &(dev->sbufsize)) < 0) {
194+
dm_del(i);
195+
continue;
196+
}
197+
}
198+
if (FD_ISSET(dev->fd, writefds)) {
199+
if (device_write(dev->fd, dev->sbuf, &(dev->sbufsize)) < 0) {
200+
dm_del(i);
201+
continue;
202+
}
203+
}
204+
if (dev->state == CONNECTED && FD_ISSET(dev->sock, writefds)) {
205+
if (device_write(dev->sock, dev->fbuf, &(dev->fbufsize)) < 0) {
206+
dm_del(i);
207+
continue;
208+
}
209+
}
210+
i++;
211+
}
212+
}
213+
214+
void dm_del(int offset)
215+
{
216+
notice(DEL, devices[offset]->path);
217+
device_delete(devices+offset);
218+
memmove(devices+offset, devices+offset+1, (--devc-offset) * sizeof(*devices));
219+
}

‎devicemanager.h

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef _DEVICE_MANAGER_H
2+
#define _DEVICE_MANAGER_H
3+
4+
#include <sys/select.h>
5+
6+
// Add device to managed devices list
7+
void dm_add(const char *device);
8+
9+
// Add fd to fd set for reading and writting
10+
void dm_select(fd_set *readfds, fd_set *writefds);
11+
12+
// Manage events for fd in readfds and writefds
13+
void dm_event(fd_set *readfds, fd_set *writefds);
14+
15+
// Remove device from managed devices list
16+
void dm_del(int offset);
17+
18+
#endif // _DEVICE_MANAGER_H

‎getsockfd.c

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#include <stdio.h>
2+
#include <unistd.h>
3+
#include <string.h>
4+
5+
#include <arpa/inet.h>
6+
#include <netdb.h>
7+
#include <netinet/in.h>
8+
9+
#include <sys/types.h>
10+
#include <sys/socket.h>
11+
12+
#ifdef __cplusplus
13+
extern "C" {
14+
#endif
15+
16+
int getsockfd(const char * host, const char * port)
17+
{
18+
struct hostent * hostent;
19+
struct servent * servent;
20+
struct sockaddr_in address;
21+
int numero, sock;
22+
23+
memset(&address, 0, sizeof(struct sockaddr_in));
24+
if (inet_aton(host, &(address.sin_addr)) == 0) {
25+
if ((hostent = gethostbyname(host)) == NULL) {
26+
fprintf(stderr, "%s: unknow host\n", __FUNCTION__);
27+
return -1;
28+
}
29+
address.sin_addr.s_addr = ((struct in_addr *) (hostent->h_addr))->s_addr;
30+
}
31+
if (sscanf(port, "%d", &numero) == 1) {
32+
address.sin_port = htons(numero);
33+
} else if ((servent = getservbyname(port, "tcp")) == NULL) {
34+
fprintf(stderr, "%s: unknow service %s\n", __FUNCTION__, port);
35+
return -1;
36+
} else {
37+
address.sin_port = servent->s_port;
38+
}
39+
address.sin_family = AF_INET;
40+
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
41+
perror("socket");
42+
return -1;
43+
}
44+
if (connect(sock, (struct sockaddr *) &address, sizeof(struct sockaddr_in)) < 0) {
45+
perror("connect");
46+
return -1;
47+
}
48+
49+
return sock;
50+
}
51+
52+
#ifdef __cplusplus
53+
}
54+
#endif

‎getttyfd.c

+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#include <termios.h>
2+
#include <stdio.h>
3+
#include <fcntl.h>
4+
#include <string.h>
5+
#include <errno.h>
6+
#include <unistd.h>
7+
8+
#ifdef __cplusplus
9+
extern "C" {
10+
#endif
11+
12+
static speed_t convertspeed(int s);
13+
14+
int getttyfd(const char * device, int s)
15+
{
16+
struct termios config;
17+
int tty;
18+
speed_t speed;
19+
20+
speed = convertspeed(s);
21+
22+
tty = open(device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
23+
if(tty == -1) {
24+
fprintf(stderr, "%s: failed to open port '%s' (%m)\n", __FUNCTION__, device);
25+
return -1;
26+
}
27+
if(!isatty(tty)) {
28+
fprintf(stderr, "%s: '%s' is not a tty (%m)\n", __FUNCTION__, device);
29+
return -1;
30+
}
31+
if(tcgetattr(tty, &config) < 0) {
32+
perror("tcgetattr");
33+
fprintf(stderr, "%s: failed to get port config\n", __FUNCTION__);
34+
return -1;
35+
}
36+
//
37+
// Input flags - Turn off input processing
38+
// convert break to null byte, no CR to NL translation,
39+
// no NL to CR translation, don't mark parity errors or breaks
40+
// no input parity check, don't strip high bit off,
41+
// no XON/XOFF software flow control
42+
//
43+
config.c_iflag &= ~(IGNBRK | BRKINT | ICRNL |
44+
INLCR | PARMRK | INPCK | ISTRIP | IXON);
45+
//
46+
// Output flags - Turn off output processing
47+
// no CR to NL translation, no NL to CR-NL translation,
48+
// no NL to CR translation, no column 0 CR suppression,
49+
// no Ctrl-D suppression, no fill characters, no case mapping,
50+
// no local output processing
51+
//
52+
// config.c_oflag &= ~(OCRNL | ONLCR | ONLRET |
53+
// ONOCR | ONOEOT| OFILL | OLCUC | OPOST);
54+
config.c_oflag = 0;
55+
//
56+
// No line processing:
57+
// echo off, echo newline off, canonical mode off,
58+
// extended input processing off, signal chars off
59+
//
60+
config.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
61+
//
62+
// Turn off character processing
63+
// clear current char size mask, no parity checking,
64+
// no output processing, force 8 bit input
65+
//
66+
config.c_cflag &= ~(CSIZE | PARENB);
67+
config.c_cflag |= CS8;
68+
//
69+
// One input byte is enough to return from read()
70+
// Inter-character timer off
71+
//
72+
config.c_cc[VMIN] = 1;
73+
config.c_cc[VTIME] = 0;
74+
//
75+
// Communication speed (simple version, using the predefined
76+
// constants)
77+
//
78+
if(cfsetispeed(&config, speed) < 0 || cfsetospeed(&config, speed) < 0) {
79+
perror("cfsetispeed");
80+
fprintf(stderr, "%s: failed to set speed\n");
81+
return -1;
82+
}
83+
//
84+
// Finally, apply the configuration
85+
//
86+
if(tcsetattr(tty, TCSAFLUSH, &config) < 0) {
87+
perror("tcsetattr");
88+
fprintf(stderr, "%s: failed to apply config\n", __FUNCTION__);
89+
return -1;
90+
}
91+
92+
return tty;
93+
}
94+
95+
static speed_t convertspeed(int speed)
96+
{
97+
switch (speed) {
98+
case 50:
99+
return B50;
100+
case 75:
101+
return B75;
102+
case 110:
103+
return B110;
104+
case 134:
105+
return B134;
106+
case 150:
107+
return B150;
108+
case 200:
109+
return B200;
110+
case 300:
111+
return B300;
112+
case 600:
113+
return B600;
114+
case 1200:
115+
return B1200;
116+
case 1800:
117+
return B1800;
118+
case 2400:
119+
return B2400;
120+
case 4800:
121+
return B4800;
122+
case 9600:
123+
return B9600;
124+
case 19200:
125+
return B19200;
126+
case 38400:
127+
return B38400;
128+
case 57600:
129+
return B57600;
130+
case 115200:
131+
return B115200;
132+
case 230400:
133+
return B230400;
134+
}
135+
fprintf(stderr, "Warning: unknow speed value %d, use 9600 instead\n", speed);
136+
return B9600;
137+
}
138+
139+
#ifdef __cplusplus
140+
}
141+
#endif

‎ini.c

+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/* inih -- simple .INI file parser
2+
3+
inih is released under the New BSD license (see LICENSE.txt). Go to the project
4+
home page for more info:
5+
6+
http://code.google.com/p/inih/
7+
8+
*/
9+
10+
#include <stdio.h>
11+
#include <ctype.h>
12+
#include <string.h>
13+
14+
#include "ini.h"
15+
16+
#define MAX_LINE 200
17+
#define MAX_SECTION 50
18+
#define MAX_NAME 50
19+
20+
/* Strip whitespace chars off end of given string, in place. Return s. */
21+
static char* rstrip(char* s)
22+
{
23+
char* p = s + strlen(s);
24+
while (p > s && isspace(*--p))
25+
*p = '\0';
26+
return s;
27+
}
28+
29+
/* Return pointer to first non-whitespace char in given string. */
30+
static char* lskip(const char* s)
31+
{
32+
while (*s && isspace(*s))
33+
s++;
34+
return (char*)s;
35+
}
36+
37+
/* Return pointer to first char c or ';' comment in given string, or pointer to
38+
null at end of string if neither found. ';' must be prefixed by a whitespace
39+
character to register as a comment. */
40+
static char* find_char_or_comment(const char* s, char c)
41+
{
42+
int was_whitespace = 0;
43+
while (*s && *s != c && !(was_whitespace && *s == ';')) {
44+
was_whitespace = isspace(*s);
45+
s++;
46+
}
47+
return (char*)s;
48+
}
49+
50+
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
51+
static char* strncpy0(char* dest, const char* src, size_t size)
52+
{
53+
strncpy(dest, src, size);
54+
dest[size - 1] = '\0';
55+
return dest;
56+
}
57+
58+
/* See documentation in header file. */
59+
int ini_parse_file(FILE* file,
60+
int (*handler)(void*, const char*, const char*,
61+
const char*),
62+
void* user)
63+
{
64+
/* Uses a fair bit of stack (use heap instead if you need to) */
65+
char line[MAX_LINE];
66+
char section[MAX_SECTION] = "";
67+
char prev_name[MAX_NAME] = "";
68+
69+
char* start;
70+
char* end;
71+
char* name;
72+
char* value;
73+
int lineno = 0;
74+
int error = 0;
75+
76+
/* Scan through file line by line */
77+
while (fgets(line, sizeof(line), file) != NULL) {
78+
lineno++;
79+
80+
start = line;
81+
#if INI_ALLOW_BOM
82+
if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
83+
(unsigned char)start[1] == 0xBB &&
84+
(unsigned char)start[2] == 0xBF) {
85+
start += 3;
86+
}
87+
#endif
88+
start = lskip(rstrip(start));
89+
90+
if (*start == ';' || *start == '#') {
91+
/* Per Python ConfigParser, allow '#' comments at start of line */
92+
}
93+
#if INI_ALLOW_MULTILINE
94+
else if (*prev_name && *start && start > line) {
95+
/* Non-black line with leading whitespace, treat as continuation
96+
of previous name's value (as per Python ConfigParser). */
97+
if (!handler(user, section, prev_name, start) && !error)
98+
error = lineno;
99+
}
100+
#endif
101+
else if (*start == '[') {
102+
/* A "[section]" line */
103+
end = find_char_or_comment(start + 1, ']');
104+
if (*end == ']') {
105+
*end = '\0';
106+
strncpy0(section, start + 1, sizeof(section));
107+
*prev_name = '\0';
108+
}
109+
else if (!error) {
110+
/* No ']' found on section line */
111+
error = lineno;
112+
}
113+
}
114+
else if (*start && *start != ';') {
115+
/* Not a comment, must be a name[=:]value pair */
116+
end = find_char_or_comment(start, '=');
117+
if (*end != '=') {
118+
end = find_char_or_comment(start, ':');
119+
}
120+
if (*end == '=' || *end == ':') {
121+
*end = '\0';
122+
name = rstrip(start);
123+
value = lskip(end + 1);
124+
end = find_char_or_comment(value, '\0');
125+
if (*end == ';')
126+
*end = '\0';
127+
rstrip(value);
128+
129+
/* Valid name[=:]value pair found, call handler */
130+
strncpy0(prev_name, name, sizeof(prev_name));
131+
if (!handler(user, section, name, value) && !error)
132+
error = lineno;
133+
}
134+
else if (!error) {
135+
/* No '=' or ':' found on name[=:]value line */
136+
error = lineno;
137+
}
138+
}
139+
}
140+
141+
return error;
142+
}
143+
144+
/* See documentation in header file. */
145+
int ini_parse(const char* filename,
146+
int (*handler)(void*, const char*, const char*, const char*),
147+
void* user)
148+
{
149+
FILE* file;
150+
int error;
151+
152+
file = fopen(filename, "r");
153+
if (!file)
154+
return -1;
155+
error = ini_parse_file(file, handler, user);
156+
fclose(file);
157+
return error;
158+
}

‎ini.h

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/* inih -- simple .INI file parser
2+
3+
inih is released under the New BSD license (see LICENSE.txt). Go to the project
4+
home page for more info:
5+
6+
http://code.google.com/p/inih/
7+
8+
*/
9+
10+
#ifndef __INI_H__
11+
#define __INI_H__
12+
13+
/* Make this header file easier to include in C++ code */
14+
#ifdef __cplusplus
15+
extern "C" {
16+
#endif
17+
18+
#include <stdio.h>
19+
20+
/* Parse given INI-style file. May have [section]s, name=value pairs
21+
(whitespace stripped), and comments starting with ';' (semicolon). Section
22+
is "" if name=value pair parsed before any section heading. name:value
23+
pairs are also supported as a concession to Python's ConfigParser.
24+
25+
For each name=value pair parsed, call handler function with given user
26+
pointer as well as section, name, and value (data only valid for duration
27+
of handler call). Handler should return nonzero on success, zero on error.
28+
29+
Returns 0 on success, line number of first error on parse error (doesn't
30+
stop on first error), or -1 on file open error.
31+
*/
32+
int ini_parse(const char* filename,
33+
int (*handler)(void* user, const char* section,
34+
const char* name, const char* value),
35+
void* user);
36+
37+
/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
38+
close the file when it's finished -- the caller must do that. */
39+
int ini_parse_file(FILE* file,
40+
int (*handler)(void* user, const char* section,
41+
const char* name, const char* value),
42+
void* user);
43+
44+
/* Nonzero to allow multi-line value parsing, in the style of Python's
45+
ConfigParser. If allowed, ini_parse() will call the handler with the same
46+
name for each subsequent line parsed. */
47+
#ifndef INI_ALLOW_MULTILINE
48+
#define INI_ALLOW_MULTILINE 1
49+
#endif
50+
51+
/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
52+
the file. See http://code.google.com/p/inih/issues/detail?id=21 */
53+
#ifndef INI_ALLOW_BOM
54+
#define INI_ALLOW_BOM 1
55+
#endif
56+
57+
#ifdef __cplusplus
58+
}
59+
#endif
60+
61+
#endif /* __INI_H__ */

‎notice.c

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include <stdlib.h>
2+
#include <stdio.h>
3+
4+
#include "notice.h"
5+
6+
void notice(enum notice type, const char *path)
7+
{
8+
notice_sock(type, path, NULL, NULL);
9+
}
10+
11+
void notice_idfail(const char *path, int id)
12+
{
13+
printf("[ID %d FAIL] %s\n", id, path);
14+
}
15+
16+
void notice_sock(enum notice type, const char *path, const char *host,
17+
const char *service)
18+
{
19+
switch (type) {
20+
case ADD:
21+
printf("[OPEN ] %s\n", path);
22+
break;
23+
case ADDFAIL:
24+
printf("[FAIL ] %s\n", path);
25+
break;
26+
case DEL:
27+
printf("[CLOSE] %s\n", path);
28+
break;
29+
case NEW:
30+
printf("[NEW ] %s\n", path);
31+
break;
32+
case CONNECT:
33+
printf("[CONNECTED] %s ↔ %s:%s\n", path, host, service);
34+
break;
35+
case SOCKFAIL:
36+
printf("[FAIL ] %s ↔ %s:%s\n", path, host, service);
37+
break;
38+
default:
39+
printf("[?????????] %s\n", path);
40+
}
41+
}

‎notice.h

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#ifndef _NOTICE_H_
2+
#define _NOTICE_H_
3+
4+
enum notice {
5+
ADD,
6+
DEL,
7+
ADDFAIL,
8+
NEW,
9+
SOCKFAIL,
10+
IDFAIL,
11+
CONNECT,
12+
};
13+
14+
void notice(enum notice type, const char *path);
15+
void notice_idfail(const char *path, int id);
16+
void notice_sock(enum notice type, const char *path, const char *host,
17+
const char *service);
18+
19+
#endif // _NOTICE_H_

‎ports.ini

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
1 = 1301
2+
2 = 1302
3+
3 = 1303
4+
4 = 1304
5+
5 = 1305

‎settings.c

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
#include <stdlib.h>
2+
#include <errno.h>
3+
4+
#include "ini.h"
5+
6+
#include "settings.h"
7+
8+
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
9+
10+
static int default_ports[MAX_ID][2] = {
11+
{ 1, 1301 },
12+
{ 2, 1302 },
13+
{ 3, 1303 },
14+
{ 4, 1304 },
15+
{ 5, 1305 },
16+
{ 0, 0 }, // Keep this line to mark the end of the array
17+
};
18+
19+
int speed = DEFAULT_SPEED;
20+
char *host = DEFAULT_HOST;
21+
static int *loaded_ports = NULL;
22+
static int loaded_ports_count = 0;
23+
static int loaded_ports_size = 0;
24+
25+
static int handler(void *user, const char *section, const char *name,
26+
const char *value)
27+
{
28+
char *ret; int id; int port;
29+
30+
id = strtol(name, &ret, 10);
31+
if (*ret != '\0' || id < 0 || id > MAX_ID) {
32+
return 0;
33+
}
34+
port = atoi(value);
35+
if (port < 1 || port > 65535) {
36+
return 0;
37+
}
38+
39+
if (loaded_ports_count == loaded_ports_size) {
40+
loaded_ports_size += 5;
41+
if ((loaded_ports = realloc(loaded_ports, loaded_ports_size
42+
* sizeof(int[2]))) == NULL) {
43+
perror("realloc");
44+
exit(EXIT_FAILURE);
45+
}
46+
}
47+
loaded_ports[loaded_ports_count * 2 + 0] = id;
48+
loaded_ports[loaded_ports_count * 2 + 1] = port;
49+
loaded_ports_count += 1;
50+
51+
return 1;
52+
}
53+
54+
int loadports(const char *filename)
55+
{
56+
int ret;
57+
58+
if ((ret = ini_parse(filename, handler, NULL)) != 0) {
59+
if (ret < 0) {
60+
printf("Warning: can't open config file '%s' (%m)\n", filename);
61+
return -1;
62+
} else {
63+
printf("Warning: errors occurred during config file"
64+
" parsing (first error at line %d)\n", ret);
65+
}
66+
}
67+
68+
return 0;
69+
}
70+
71+
int getportbyid(int id)
72+
{
73+
int i = 0;
74+
int port;
75+
76+
if (loaded_ports) {
77+
for (i = 0 ; i < loaded_ports_count ; i++) {
78+
port = loaded_ports[i * 2 + 1];
79+
if (loaded_ports[i * 2 + 0] == id)
80+
break;
81+
}
82+
if (i == loaded_ports_count) {
83+
port = 0;
84+
}
85+
} else {
86+
do {
87+
port = default_ports[i][1];
88+
if (default_ports[i][0] == id)
89+
break;
90+
i++;
91+
} while (port != 0);
92+
}
93+
94+
return port;
95+
}

‎settings.h

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#ifndef _SETTINGS_H_
2+
#define _SETTINGS_H_
3+
4+
#define DEFAULT_SPEED 9600
5+
#define DEFAULT_HOST "localhost"
6+
#define MAX_ID 255
7+
8+
extern int speed;
9+
extern char *host;
10+
11+
/* Load ports list from config file. */
12+
int loadports(const char *filename);
13+
14+
/* Return port number associated with provides id.
15+
* If no port is associated with this id, return 0.
16+
*/
17+
int getportbyid(int id);
18+
19+
#endif // _SETTINGS_H_

‎usbdaemon.c

+224
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
#include <stdlib.h>
2+
#include <stdio.h>
3+
#include <errno.h>
4+
#include <string.h>
5+
#include <unistd.h>
6+
#include <sys/types.h>
7+
#include <dirent.h>
8+
#include <fcntl.h>
9+
#include <sys/inotify.h>
10+
11+
#include "settings.h"
12+
13+
#define EVENT_SIZE (sizeof(struct inotify_event))
14+
#define BUF_LEN (8*(EVENT_SIZE+16))
15+
16+
#define ENV_PREFIX "USBDAEMON"
17+
#define MAX_DEVICE 16
18+
19+
const char *basedir = "/dev";
20+
21+
void usage(const char *cmd);
22+
int addexistingdevices(const char *dir);
23+
int getinotifyfd(const char *dir);
24+
void gateway(int inotifyfd);
25+
int filter(const char *filename);
26+
27+
int main(int argc, char *argv[])
28+
{
29+
int option, inotifyfd;
30+
char *env;
31+
char *opt_host = NULL;
32+
char *configfile = NULL;
33+
char *opt_basedir = NULL;
34+
35+
env = getenv(ENV_PREFIX"_HOST");
36+
if ((env != NULL) && (strlen(env) != 0)) {
37+
if ((opt_host = malloc(strlen(env) + 1)) == NULL) {
38+
perror("malloc");
39+
exit(EXIT_FAILURE);
40+
}
41+
strcpy(opt_host, env);
42+
host = opt_host;
43+
}
44+
env = getenv(ENV_PREFIX"_SPEED");
45+
if ((env != NULL) && (strlen(env) != 0)) {
46+
sscanf(env, "%d", &speed);
47+
}
48+
env = getenv(ENV_PREFIX"_CONFIG");
49+
if ((env != NULL) && (strlen(env) != 0)) {
50+
if ((configfile = malloc(strlen(env) + 1)) == NULL) {
51+
perror("malloc");
52+
exit(EXIT_FAILURE);
53+
}
54+
strcpy(configfile, env);
55+
}
56+
env = getenv(ENV_PREFIX"_DIR");
57+
if ((env != NULL) && (strlen(env) != 0)) {
58+
if ((opt_basedir = malloc(strlen(env) + 1)) == NULL) {
59+
perror("malloc");
60+
exit(EXIT_FAILURE);
61+
}
62+
strcpy(opt_basedir, env);
63+
basedir = opt_basedir;
64+
}
65+
66+
opterr = 1;
67+
while (1) {
68+
option = getopt(argc, argv, "h:s:c:d:");
69+
if (option == -1)
70+
break;
71+
switch (option) {
72+
case 'h':
73+
if ((opt_host = malloc(strlen(optarg) + 1)) == NULL) {
74+
perror("malloc");
75+
exit(EXIT_FAILURE);
76+
}
77+
strcpy(opt_host, optarg);
78+
host = opt_host;
79+
break;
80+
case 's':
81+
sscanf(optarg, "%d", &speed);
82+
break;
83+
case 'c':
84+
if ((configfile = malloc(strlen(optarg) + 1)) == NULL) {
85+
perror("malloc");
86+
exit(EXIT_FAILURE);
87+
}
88+
strcpy(configfile, optarg);
89+
break;
90+
case 'd':
91+
if ((opt_basedir = malloc(strlen(optarg) + 1)) == NULL) {
92+
perror("malloc");
93+
exit(EXIT_FAILURE);
94+
}
95+
strcpy(opt_basedir, optarg);
96+
basedir = opt_basedir;
97+
break;
98+
case '?':
99+
usage(argv[0]);
100+
exit(EXIT_FAILURE);
101+
default:
102+
break;
103+
}
104+
}
105+
106+
printf("Gateway settings:\n");
107+
printf("\tHost: %s\n", host);
108+
printf("\tSpeed: %d\n", speed);
109+
printf("\tMonitoring device in: %s\n", basedir);
110+
if (configfile) {
111+
printf("\tConfig file: %s\n", configfile);
112+
if (loadports(configfile) < 0) {
113+
fprintf(stderr, "Warning: using defaults ports instead\n");
114+
}
115+
}
116+
117+
if (addexistingdevices(basedir) < 0) {
118+
fprintf(stderr, "Warning: already connected device not managed\n");
119+
}
120+
121+
if ((inotifyfd = getinotifyfd(basedir)) < 0) {
122+
fprintf(stderr, "Warning: monitoring disabled");
123+
}
124+
125+
gateway(inotifyfd);
126+
127+
return 0;
128+
}
129+
130+
int filter(const char *filename)
131+
{
132+
int a;
133+
return sscanf(filename, "ttyUSB%d", &a) == 1;
134+
}
135+
136+
int addexistingdevices(const char *basedir)
137+
{
138+
struct dirent *item;
139+
char path[256];
140+
DIR *dir = opendir(basedir);
141+
142+
if (dir == NULL) {
143+
perror("opendir");
144+
return -1;
145+
}
146+
while (item = readdir(dir)) {
147+
if (filter(item->d_name)) {
148+
sprintf(path, "%s/%s", basedir, item->d_name);
149+
dm_add(path);
150+
}
151+
}
152+
153+
closedir(dir);
154+
155+
return 0;
156+
}
157+
158+
int getinotifyfd(const char *dir)
159+
{
160+
int fd, wd;
161+
162+
if ((fd = inotify_init1(O_NONBLOCK)) < 0) {
163+
perror("intotify_init1");
164+
return -1;
165+
}
166+
167+
if (inotify_add_watch(fd, dir, IN_CREATE) < 0) {
168+
perror("inotify_add_watch");
169+
return -1;
170+
}
171+
172+
return fd;
173+
}
174+
175+
void gateway(int inotifyfd)
176+
{
177+
int length, i;
178+
char buffer[BUF_LEN];
179+
char path[256];
180+
fd_set readfds, writefds;
181+
182+
while (1) {
183+
FD_ZERO(&readfds);
184+
if (inotifyfd > -1) {
185+
FD_SET(inotifyfd, &readfds);
186+
}
187+
FD_ZERO(&writefds);
188+
dm_select(&readfds, &writefds);
189+
190+
if (select(FD_SETSIZE, &readfds, &writefds, NULL, NULL) < 0) {
191+
if (errno == EINTR) {
192+
continue;
193+
} else {
194+
perror("select");
195+
exit(EXIT_FAILURE); // FIXME
196+
}
197+
}
198+
199+
if (FD_ISSET(inotifyfd, &readfds)) {
200+
if ((length = read(inotifyfd, buffer, BUF_LEN)) < 0) {
201+
perror("read");
202+
exit(EXIT_FAILURE); // FIXME
203+
}
204+
i = 0;
205+
while (i < length) {
206+
struct inotify_event *event = (struct inotify_event*)&(buffer[i]);
207+
if (event->len && !(event->mask & IN_ISDIR)) {
208+
if (filter(event->name)) {
209+
sprintf(path, "%s/%s", basedir, event->name);
210+
dm_scheduledadd(path);
211+
}
212+
}
213+
i += EVENT_SIZE + event->len;
214+
}
215+
}
216+
217+
dm_event(&readfds, &writefds);
218+
}
219+
}
220+
221+
void usage(const char *cmd)
222+
{
223+
printf("Usage: %s [-h host] [-s speed] [-c config_file] [-d device_dir]\n", cmd);
224+
}

0 commit comments

Comments
 (0)
Please sign in to comment.