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$
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 && daemon(0, 0) < 0) {
105		syslog(LOG_ERR, "Could not daemon(0, 0). %s (%d)",
106			strerror(errno), errno);
107		exit(1);
108	}
109
110	/* Write PID file */
111	snprintf(p, sizeof(p), "/var/run/%s.%s.pid", hcseriald, name);
112	f = fopen(p, "w");
113	if (f == NULL) {
114		syslog(LOG_ERR, "Could not fopen(%s). %s (%d)",
115			p, strerror(errno), errno);
116		exit(1);
117	}
118	fprintf(f, "%d", getpid());
119	fclose(f);
120
121	/* Install signal handler */
122	memset(&sa, 0, sizeof(sa));
123	sa.sa_handler = sighandler;
124
125	if (sigaction(SIGTERM, &sa, NULL) < 0) {
126		syslog(LOG_ERR, "Could not sigaction(SIGTERM). %s (%d)",
127			strerror(errno), errno);
128		exit(1);
129	}
130
131	if (sigaction(SIGHUP, &sa, NULL) < 0) {
132		syslog(LOG_ERR, "Could not sigaction(SIGHUP). %s (%d)",
133			strerror(errno), errno);
134		exit(1);
135	}
136
137	if (sigaction(SIGINT, &sa, NULL) < 0) {
138		syslog(LOG_ERR, "Could not sigaction(SIGINT). %s (%d)",
139			strerror(errno), errno);
140		exit(1);
141	}
142
143	/* Keep running */
144	while (!done)
145		select(0, NULL, NULL, NULL, NULL);
146
147	/* Remove PID file and close device */
148	unlink(p);
149	close(n);
150	closelog();
151
152	return (0);
153} /* main */
154
155/* Open terminal, set settings, push H4 line discipline and set node name */
156static int
157open_device(char const *device, speed_t speed, char const *name)
158{
159	int		fd, disc, cs, ds;
160	struct termios	t;
161	struct nodeinfo	ni;
162	struct ngm_name	n;
163	char		p[NG_NODESIZ];
164
165	/* Open terminal device and setup H4 line discipline */
166	fd = open(device, O_RDWR|O_NOCTTY);
167	if (fd < 0) {
168		syslog(LOG_ERR, "Could not open(%s). %s (%d)",
169			device, strerror(errno), errno);
170		exit(1);
171	}
172
173	tcflush(fd, TCIOFLUSH);
174
175	if (tcgetattr(fd, &t) < 0) {
176		syslog(LOG_ERR, "Could not tcgetattr(%s). %s (%d)",
177			device, strerror(errno), errno);
178		exit(1);
179	}
180
181	cfmakeraw(&t);
182
183	t.c_cflag |= CLOCAL;	/* clocal */
184	t.c_cflag &= ~CSIZE;	/* cs8 */
185	t.c_cflag |= CS8; 	/* cs8 */
186	t.c_cflag &= ~PARENB;	/* -parenb */
187	t.c_cflag &= ~CSTOPB;	/* -cstopb */
188	t.c_cflag |= CRTSCTS;	/* crtscts */
189
190	if (tcsetattr(fd, TCSANOW, &t) < 0) {
191		syslog(LOG_ERR, "Could not tcsetattr(%s). %s (%d)",
192			device, strerror(errno), errno);
193		exit(1);
194	}
195
196	tcflush(fd, TCIOFLUSH);
197
198	if (cfsetspeed(&t, speed) < 0) {
199		syslog(LOG_ERR, "Could not cfsetspeed(%s). %s (%d)",
200			device, strerror(errno), errno);
201		exit(1);
202	}
203
204	if (tcsetattr(fd, TCSANOW, &t) < 0) {
205		syslog(LOG_ERR, "Could not tcsetattr(%s). %s (%d)",
206			device, strerror(errno), errno);
207		exit(1);
208	}
209
210	disc = H4DISC;
211	if (ioctl(fd, TIOCSETD, &disc) < 0) {
212		syslog(LOG_ERR, "Could not ioctl(%s, TIOCSETD, %d). %s (%d)",
213			device, disc, strerror(errno), errno);
214		exit(1);
215	}
216
217	/* Get default name of the Netgraph node */
218	memset(&ni, 0, sizeof(ni));
219	if (ioctl(fd, NGIOCGINFO, &ni) < 0) {
220		syslog(LOG_ERR, "Could not ioctl(%d, NGIOGINFO). %s (%d)",
221			fd, strerror(errno), errno);
222		exit(1);
223	}
224
225	/* Assign new name to the Netgraph node */
226	snprintf(p, sizeof(p), "%s:", ni.name);
227	snprintf(n.name, sizeof(n.name), "%s", name);
228
229	if (NgMkSockNode(NULL, &cs, &ds) < 0) {
230		syslog(LOG_ERR, "Could not NgMkSockNode(). %s (%d)",
231			strerror(errno), errno);
232		exit(1);
233	}
234
235	if (NgSendMsg(cs, p, NGM_GENERIC_COOKIE, NGM_NAME, &n, sizeof(n)) < 0) {
236		syslog(LOG_ERR, "Could not NgSendMsg(%d, %s, NGM_NAME, %s). " \
237			"%s (%d)", cs, p, n.name, strerror(errno), errno);
238		exit(1);
239	}
240
241	close(cs);
242	close(ds);
243
244	return (fd);
245} /* open_device */
246
247/* Signal handler */
248static void
249sighandler(int s)
250{
251	done = 1;
252} /* sighandler */
253
254/* Usage */
255static void
256usage(void)
257{
258	fprintf(stderr, "Usage: %s -f device -n node_name [-s speed -d -h]\n" \
259			"Where:\n" \
260			"\t-f device    tty device name, ex. /dev/cuau1\n" \
261			"\t-n node_name set Netgraph node name to node_name\n" \
262			"\t-s speed     set tty speed, ex. 115200\n" \
263			"\t-d           run in foreground\n" \
264			"\t-h           display this message\n",
265			hcseriald);
266	exit(255);
267} /* usage */
268
269