hcseriald.c revision 121054
1/*
2 * hcseriald.c
3 *
4 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $Id: hcseriald.c,v 1.3 2003/05/21 22:40:32 max Exp $
29 * $FreeBSD: head/usr.sbin/bluetooth/hcseriald/hcseriald.c 121054 2003-10-12 22:04:24Z emax $
30 */
31
32#include <sys/types.h>
33#include <sys/ioctl.h>
34
35#include <netgraph/ng_message.h>
36#include <netgraph.h>
37#include <netgraph/bluetooth/include/ng_h4.h>
38
39#include <errno.h>
40#include <fcntl.h>
41#include <signal.h>
42#include <stdarg.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <syslog.h>
47#include <termios.h>
48#include <unistd.h>
49
50/* Prototypes */
51static int	open_device	(char const *, speed_t, char const *);
52static void	sighandler	(int);
53static void	usage		();
54
55static char const * const	hcseriald = "hcseriald";
56static int			done = 0;
57
58int
59main(int argc, char *argv[])
60{
61	char			*device = NULL, *name = NULL;
62	speed_t			 speed = 115200;
63	int			 n, detach = 1;
64	char			 p[FILENAME_MAX];
65	FILE			*f = NULL;
66	struct sigaction	 sa;
67
68	/* Process command line arguments */
69	while ((n = getopt(argc, argv, "df:n:s:h")) != -1) {
70		switch (n) {
71		case 'd':
72			detach = 0;
73			break;
74
75		case 'f':
76			device = optarg;
77			break;
78
79		case 'n':
80			name = optarg;
81			break;
82
83		case 's':
84			speed = atoi(optarg);
85			if (speed < 0)
86				usage(argv[0]);
87			break;
88
89		case 'h':
90		default:
91			usage(argv[0]);
92			break;
93		}
94	}
95
96	if (device == NULL || name == NULL)
97		usage(argv[0]);
98
99	openlog(hcseriald, LOG_PID | LOG_NDELAY, LOG_USER);
100
101	/* Open device */
102	n = open_device(device, speed, name);
103
104	if (detach) {
105		pid_t	pid = fork();
106
107		if (pid == (pid_t) -1) {
108			syslog(LOG_ERR, "Could not fork(). %s (%d)",
109				strerror(errno), errno);
110			exit(1);
111		}
112
113		if (pid != 0)
114			exit(0);
115
116		if (daemon(0, 0) < 0) {
117			syslog(LOG_ERR, "Could not daemon(0, 0). %s (%d)",
118				strerror(errno), errno);
119			exit(1);
120		}
121	}
122
123	/* Write PID file */
124	snprintf(p, sizeof(p), "/var/run/%s.%s.pid", hcseriald, name);
125	f = fopen(p, "w");
126	if (f == NULL) {
127		syslog(LOG_ERR, "Could not fopen(%s). %s (%d)",
128			p, strerror(errno), errno);
129		exit(1);
130	}
131	fprintf(f, "%d", getpid());
132	fclose(f);
133
134	/* Install signal handler */
135	memset(&sa, 0, sizeof(sa));
136	sa.sa_handler = sighandler;
137
138	if (sigaction(SIGTERM, &sa, NULL) < 0) {
139		syslog(LOG_ERR, "Could not sigaction(SIGTERM). %s (%d)",
140			strerror(errno), errno);
141		exit(1);
142	}
143
144	if (sigaction(SIGHUP, &sa, NULL) < 0) {
145		syslog(LOG_ERR, "Could not sigaction(SIGHUP). %s (%d)",
146			strerror(errno), errno);
147		exit(1);
148	}
149
150	if (sigaction(SIGINT, &sa, NULL) < 0) {
151		syslog(LOG_ERR, "Could not sigaction(SIGINT). %s (%d)",
152			strerror(errno), errno);
153		exit(1);
154	}
155
156	/* Keep running */
157	while (!done)
158		select(0, NULL, NULL, NULL, NULL);
159
160	/* Remove PID file and close device */
161	unlink(p);
162	close(n);
163	closelog();
164
165	return (0);
166} /* main */
167
168/* Open terminal, set settings, push H4 line discipline and set node name */
169static int
170open_device(char const *device, speed_t speed, char const *name)
171{
172	int		fd, disc, cs, ds;
173	struct termios	t;
174	struct nodeinfo	ni;
175	struct ngm_name	n;
176	char		p[NG_NODELEN + 1];
177
178	/* Open terminal device and setup H4 line discipline */
179	fd = open(device, O_RDWR|O_NOCTTY);
180	if (fd < 0) {
181		syslog(LOG_ERR, "Could not open(%s). %s (%d)",
182			device, strerror(errno), errno);
183		exit(1);
184	}
185
186	tcflush(fd, TCIOFLUSH);
187
188	if (tcgetattr(fd, &t) < 0) {
189		syslog(LOG_ERR, "Could not tcgetattr(%s). %s (%d)",
190			device, strerror(errno), errno);
191		exit(1);
192	}
193
194	cfmakeraw(&t);
195
196	t.c_cflag |= CLOCAL;	/* clocal */
197	t.c_cflag &= ~CSIZE;	/* cs8 */
198	t.c_cflag |= CS8; 	/* cs8 */
199	t.c_cflag &= ~PARENB;	/* -parenb */
200	t.c_cflag &= ~CSTOPB;	/* -cstopb */
201	t.c_cflag |= CRTSCTS;	/* crtscts */
202
203	if (tcsetattr(fd, TCSANOW, &t) < 0) {
204		syslog(LOG_ERR, "Could not tcsetattr(%s). %s (%d)",
205			device, strerror(errno), errno);
206		exit(1);
207	}
208
209	tcflush(fd, TCIOFLUSH);
210
211	if (cfsetspeed(&t, speed) < 0) {
212		syslog(LOG_ERR, "Could not cfsetspeed(%s). %s (%d)",
213			device, strerror(errno), errno);
214		exit(1);
215	}
216
217	if (tcsetattr(fd, TCSANOW, &t) < 0) {
218		syslog(LOG_ERR, "Could not tcsetattr(%s). %s (%d)",
219			device, strerror(errno), errno);
220		exit(1);
221	}
222
223	disc = H4DISC;
224	if (ioctl(fd, TIOCSETD, &disc) < 0) {
225		syslog(LOG_ERR, "Could not ioctl(%s, TIOCSETD, %d). %s (%d)",
226			device, disc, strerror(errno), errno);
227		exit(1);
228	}
229
230	/* Get default name of the Netgraph node */
231	memset(&ni, 0, sizeof(ni));
232	if (ioctl(fd, NGIOCGINFO, &ni) < 0) {
233		syslog(LOG_ERR, "Could not ioctl(%d, NGIOGINFO). %s (%d)",
234			fd, strerror(errno), errno);
235		exit(1);
236	}
237
238	/* Assign new name to the Netgraph node */
239	snprintf(p, sizeof(p), "%s:", ni.name);
240	snprintf(n.name, sizeof(n.name), "%s", name);
241
242	if (NgMkSockNode(NULL, &cs, &ds) < 0) {
243		syslog(LOG_ERR, "Could not NgMkSockNode(). %s (%d)",
244			strerror(errno), errno);
245		exit(1);
246	}
247
248	if (NgSendMsg(cs, p, NGM_GENERIC_COOKIE, NGM_NAME, &n, sizeof(n)) < 0) {
249		syslog(LOG_ERR, "Could not NgSendMsg(%d, %s, NGM_NAME, %s). " \
250			"%s (%d)", cs, p, n.name, strerror(errno), errno);
251		exit(1);
252	}
253
254	close(cs);
255	close(ds);
256
257	return (fd);
258} /* open_device */
259
260/* Signal handler */
261static void
262sighandler(int s)
263{
264	done = 1;
265} /* sighandler */
266
267/* Usage */
268static void
269usage(void)
270{
271	fprintf(stderr, "Usage: %s -f device -n node_name [-s speed -d -h]\n" \
272			"Where:\n" \
273			"\t-f device    tty device name, ex. /dev/cuaa1\n" \
274			"\t-n node_name set Netgraph node name to node_name\n" \
275			"\t-s speed     set tty speed, ex. 115200\n" \
276			"\t-d           run in foreground\n" \
277			"\t-h           display this message\n",
278			hcseriald);
279	exit(255);
280} /* usage */
281
282