rfcomm_sppd.c revision 1.1 1 1.1 gdamore /* $NetBSD: rfcomm_sppd.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */
2 1.1 gdamore
3 1.1 gdamore /*-
4 1.1 gdamore * Copyright (c) 2006 Itronix Inc.
5 1.1 gdamore * All rights reserved.
6 1.1 gdamore *
7 1.1 gdamore * Redistribution and use in source and binary forms, with or without
8 1.1 gdamore * modification, are permitted provided that the following conditions
9 1.1 gdamore * are met:
10 1.1 gdamore * 1. Redistributions of source code must retain the above copyright
11 1.1 gdamore * notice, this list of conditions and the following disclaimer.
12 1.1 gdamore * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 gdamore * notice, this list of conditions and the following disclaimer in the
14 1.1 gdamore * documentation and/or other materials provided with the distribution.
15 1.1 gdamore * 3. The name of Itronix Inc. may not be used to endorse
16 1.1 gdamore * or promote products derived from this software without specific
17 1.1 gdamore * prior written permission.
18 1.1 gdamore *
19 1.1 gdamore * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
20 1.1 gdamore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 gdamore * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 gdamore * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
23 1.1 gdamore * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 1.1 gdamore * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 1.1 gdamore * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 1.1 gdamore * ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 gdamore * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 gdamore * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 gdamore * POSSIBILITY OF SUCH DAMAGE.
30 1.1 gdamore */
31 1.1 gdamore /*
32 1.1 gdamore * rfcomm_sppd.c
33 1.1 gdamore *
34 1.1 gdamore * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin (at) yahoo.com>
35 1.1 gdamore * All rights reserved.
36 1.1 gdamore *
37 1.1 gdamore * Redistribution and use in source and binary forms, with or without
38 1.1 gdamore * modification, are permitted provided that the following conditions
39 1.1 gdamore * are met:
40 1.1 gdamore * 1. Redistributions of source code must retain the above copyright
41 1.1 gdamore * notice, this list of conditions and the following disclaimer.
42 1.1 gdamore * 2. Redistributions in binary form must reproduce the above copyright
43 1.1 gdamore * notice, this list of conditions and the following disclaimer in the
44 1.1 gdamore * documentation and/or other materials provided with the distribution.
45 1.1 gdamore *
46 1.1 gdamore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
47 1.1 gdamore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 1.1 gdamore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 1.1 gdamore * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
50 1.1 gdamore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 1.1 gdamore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 1.1 gdamore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 1.1 gdamore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 1.1 gdamore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 1.1 gdamore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 1.1 gdamore * SUCH DAMAGE.
57 1.1 gdamore *
58 1.1 gdamore * $Id: rfcomm_sppd.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $
59 1.1 gdamore * $FreeBSD: src/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.c,v 1.8 2005/12/07 19:41:58 emax Exp $
60 1.1 gdamore */
61 1.1 gdamore
62 1.1 gdamore #include <sys/cdefs.h>
63 1.1 gdamore __COPYRIGHT("@(#) Copyright (c) 2006 Itronix, Inc.\n"
64 1.1 gdamore "@(#) Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin (at) yahoo.com>\n"
65 1.1 gdamore "All rights reserved.\n");
66 1.1 gdamore __RCSID("$NetBSD: rfcomm_sppd.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $");
67 1.1 gdamore
68 1.1 gdamore #include <bluetooth.h>
69 1.1 gdamore #include <ctype.h>
70 1.1 gdamore #include <err.h>
71 1.1 gdamore #include <errno.h>
72 1.1 gdamore #include <fcntl.h>
73 1.1 gdamore #include <grp.h>
74 1.1 gdamore #include <limits.h>
75 1.1 gdamore #include <paths.h>
76 1.1 gdamore #include <sdp.h>
77 1.1 gdamore #include <signal.h>
78 1.1 gdamore #include <stdarg.h>
79 1.1 gdamore #include <stdio.h>
80 1.1 gdamore #include <stdlib.h>
81 1.1 gdamore #include <string.h>
82 1.1 gdamore #include <syslog.h>
83 1.1 gdamore #include <termios.h>
84 1.1 gdamore #include <unistd.h>
85 1.1 gdamore
86 1.1 gdamore #include "rfcomm_sdp.h"
87 1.1 gdamore
88 1.1 gdamore #define SPPD_IDENT "rfcomm_sppd"
89 1.1 gdamore #define SPPD_BUFFER_SIZE 1024
90 1.1 gdamore #define max(a, b) (((a) > (b))? (a) : (b))
91 1.1 gdamore
92 1.1 gdamore static int sppd_ttys_open (char const *tty, int *amaster, int *aslave);
93 1.1 gdamore static int sppd_read (int fd, char *buffer, size_t size);
94 1.1 gdamore static int sppd_write (int fd, char *buffer, size_t size);
95 1.1 gdamore static void sppd_sighandler (int s);
96 1.1 gdamore static void usage (void);
97 1.1 gdamore
98 1.1 gdamore static int done; /* are we done? */
99 1.1 gdamore
100 1.1 gdamore /* Main */
101 1.1 gdamore int
102 1.1 gdamore main(int argc, char *argv[])
103 1.1 gdamore {
104 1.1 gdamore struct sigaction sa;
105 1.1 gdamore struct sockaddr_bt ra;
106 1.1 gdamore bdaddr_t laddr, raddr;
107 1.1 gdamore uint8_t channel;
108 1.1 gdamore int n, background, service,
109 1.1 gdamore s, amaster, aslave, fd;
110 1.1 gdamore fd_set rfd;
111 1.1 gdamore char *tty = NULL, *ep = NULL, buf[SPPD_BUFFER_SIZE];
112 1.1 gdamore
113 1.1 gdamore bdaddr_copy(&laddr, BDADDR_ANY);
114 1.1 gdamore bdaddr_copy(&raddr, BDADDR_ANY);
115 1.1 gdamore background = channel = 0;
116 1.1 gdamore service = SDP_SERVICE_CLASS_SERIAL_PORT;
117 1.1 gdamore
118 1.1 gdamore /* Parse command line options */
119 1.1 gdamore while ((n = getopt(argc, argv, "a:bc:d:t:h")) != -1) {
120 1.1 gdamore switch (n) {
121 1.1 gdamore case 'a': /* BDADDR */
122 1.1 gdamore if (!bt_aton(optarg, &raddr)) {
123 1.1 gdamore struct hostent *he = NULL;
124 1.1 gdamore
125 1.1 gdamore if ((he = bt_gethostbyname(optarg)) == NULL)
126 1.1 gdamore errx(EXIT_FAILURE,
127 1.1 gdamore "%s: %s", optarg, hstrerror(h_errno));
128 1.1 gdamore
129 1.1 gdamore bdaddr_copy(&raddr, (bdaddr_t *)he->h_addr);
130 1.1 gdamore }
131 1.1 gdamore break;
132 1.1 gdamore
133 1.1 gdamore case 'c': /* RFCOMM channel */
134 1.1 gdamore channel = strtoul(optarg, &ep, 10);
135 1.1 gdamore if (*ep != '\0') {
136 1.1 gdamore channel = 0;
137 1.1 gdamore switch (tolower((int)optarg[0])) {
138 1.1 gdamore case 'd': /* DialUp Networking */
139 1.1 gdamore service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
140 1.1 gdamore break;
141 1.1 gdamore
142 1.1 gdamore case 'f': /* Fax */
143 1.1 gdamore service = SDP_SERVICE_CLASS_FAX;
144 1.1 gdamore break;
145 1.1 gdamore
146 1.1 gdamore case 'l': /* LAN */
147 1.1 gdamore service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
148 1.1 gdamore break;
149 1.1 gdamore
150 1.1 gdamore case 's': /* Serial Port */
151 1.1 gdamore service = SDP_SERVICE_CLASS_SERIAL_PORT;
152 1.1 gdamore break;
153 1.1 gdamore
154 1.1 gdamore default:
155 1.1 gdamore errx(EXIT_FAILURE, "Unknown service name: %s",
156 1.1 gdamore optarg);
157 1.1 gdamore /* NOT REACHED */
158 1.1 gdamore }
159 1.1 gdamore }
160 1.1 gdamore break;
161 1.1 gdamore
162 1.1 gdamore case 'b': /* Run in background */
163 1.1 gdamore background = 1;
164 1.1 gdamore break;
165 1.1 gdamore
166 1.1 gdamore case 'd': /* device */
167 1.1 gdamore if (!bt_devaddr(optarg, &laddr))
168 1.1 gdamore err(EXIT_FAILURE, "%s", optarg);
169 1.1 gdamore break;
170 1.1 gdamore
171 1.1 gdamore case 't': /* Slave TTY name */
172 1.1 gdamore if (optarg[0] != '/')
173 1.1 gdamore asprintf(&tty, "%s%s", _PATH_DEV, optarg);
174 1.1 gdamore else
175 1.1 gdamore tty = optarg;
176 1.1 gdamore break;
177 1.1 gdamore
178 1.1 gdamore case 'h':
179 1.1 gdamore default:
180 1.1 gdamore usage();
181 1.1 gdamore /* NOT REACHED */
182 1.1 gdamore }
183 1.1 gdamore }
184 1.1 gdamore
185 1.1 gdamore /* Check if we have everything we need */
186 1.1 gdamore if (bdaddr_any(&raddr))
187 1.1 gdamore usage();
188 1.1 gdamore /* NOT REACHED */
189 1.1 gdamore
190 1.1 gdamore /* Set signal handlers */
191 1.1 gdamore memset(&sa, 0, sizeof(sa));
192 1.1 gdamore sa.sa_handler = sppd_sighandler;
193 1.1 gdamore
194 1.1 gdamore if (sigaction(SIGTERM, &sa, NULL) < 0)
195 1.1 gdamore err(EXIT_FAILURE, "Could not sigaction(SIGTERM)");
196 1.1 gdamore
197 1.1 gdamore if (sigaction(SIGHUP, &sa, NULL) < 0)
198 1.1 gdamore err(EXIT_FAILURE, "Could not sigaction(SIGHUP)");
199 1.1 gdamore
200 1.1 gdamore if (sigaction(SIGINT, &sa, NULL) < 0)
201 1.1 gdamore err(EXIT_FAILURE, "Could not sigaction(SIGINT)");
202 1.1 gdamore
203 1.1 gdamore sa.sa_handler = SIG_IGN;
204 1.1 gdamore sa.sa_flags = SA_NOCLDWAIT;
205 1.1 gdamore
206 1.1 gdamore if (sigaction(SIGCHLD, &sa, NULL) < 0)
207 1.1 gdamore err(EXIT_FAILURE, "Could not sigaction(SIGCHLD)");
208 1.1 gdamore
209 1.1 gdamore /* Check channel, if was not set then obtain it via SDP */
210 1.1 gdamore if (channel == 0 && service != 0)
211 1.1 gdamore if (rfcomm_channel_lookup(&laddr, &raddr,
212 1.1 gdamore service, &channel, &n) != 0)
213 1.1 gdamore errx(EXIT_FAILURE,
214 1.1 gdamore "Could not obtain RFCOMM channel: %s",
215 1.1 gdamore strerror(n));
216 1.1 gdamore
217 1.1 gdamore if (channel < 1 || channel > 30)
218 1.1 gdamore errx(EXIT_FAILURE,
219 1.1 gdamore "Invalid RFCOMM channel number %d", channel);
220 1.1 gdamore
221 1.1 gdamore /* Open TTYs */
222 1.1 gdamore if (tty == NULL) {
223 1.1 gdamore if (background)
224 1.1 gdamore usage();
225 1.1 gdamore
226 1.1 gdamore aslave = 0;
227 1.1 gdamore amaster = STDIN_FILENO;
228 1.1 gdamore fd = STDOUT_FILENO;
229 1.1 gdamore } else {
230 1.1 gdamore if (sppd_ttys_open(tty, &amaster, &aslave) < 0)
231 1.1 gdamore exit(EXIT_FAILURE);
232 1.1 gdamore
233 1.1 gdamore fd = amaster;
234 1.1 gdamore }
235 1.1 gdamore
236 1.1 gdamore /* Open RFCOMM connection */
237 1.1 gdamore memset(&ra, 0, sizeof(ra));
238 1.1 gdamore ra.bt_len = sizeof(ra);
239 1.1 gdamore ra.bt_family = AF_BLUETOOTH;
240 1.1 gdamore
241 1.1 gdamore s = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
242 1.1 gdamore if (s < 0)
243 1.1 gdamore err(EXIT_FAILURE, "Could not create socket");
244 1.1 gdamore
245 1.1 gdamore bdaddr_copy(&ra.bt_bdaddr, &laddr);
246 1.1 gdamore if (bind(s, (struct sockaddr *) &ra, sizeof(ra)) < 0)
247 1.1 gdamore err(EXIT_FAILURE, "Could not bind socket");
248 1.1 gdamore
249 1.1 gdamore ra.bt_channel = channel;
250 1.1 gdamore bdaddr_copy(&ra.bt_bdaddr, &raddr);
251 1.1 gdamore
252 1.1 gdamore if (connect(s, (struct sockaddr *) &ra, sizeof(ra)) < 0)
253 1.1 gdamore err(EXIT_FAILURE, "Could not connect socket");
254 1.1 gdamore
255 1.1 gdamore /* Became daemon if required */
256 1.1 gdamore if (background) {
257 1.1 gdamore switch (fork()) {
258 1.1 gdamore case -1:
259 1.1 gdamore err(EXIT_FAILURE, "Could not fork()");
260 1.1 gdamore /* NOT REACHED */
261 1.1 gdamore
262 1.1 gdamore case 0:
263 1.1 gdamore exit(EXIT_SUCCESS);
264 1.1 gdamore /* NOT REACHED */
265 1.1 gdamore
266 1.1 gdamore default:
267 1.1 gdamore if (daemon(0, 0) < 0)
268 1.1 gdamore err(EXIT_FAILURE, "Could not daemon()");
269 1.1 gdamore break;
270 1.1 gdamore }
271 1.1 gdamore }
272 1.1 gdamore
273 1.1 gdamore openlog(SPPD_IDENT, LOG_NDELAY|LOG_PERROR|LOG_PID, LOG_DAEMON);
274 1.1 gdamore syslog(LOG_INFO, "Starting on %s...",
275 1.1 gdamore (tty != NULL) ? tty : "stdin/stdout");
276 1.1 gdamore
277 1.1 gdamore for (done = 0; !done; ) {
278 1.1 gdamore FD_ZERO(&rfd);
279 1.1 gdamore FD_SET(amaster, &rfd);
280 1.1 gdamore FD_SET(s, &rfd);
281 1.1 gdamore
282 1.1 gdamore n = select(max(amaster, s) + 1, &rfd, NULL, NULL, NULL);
283 1.1 gdamore if (n < 0) {
284 1.1 gdamore if (errno == EINTR)
285 1.1 gdamore continue;
286 1.1 gdamore
287 1.1 gdamore syslog(LOG_ERR, "Could not select(). %s",
288 1.1 gdamore strerror(errno));
289 1.1 gdamore exit(EXIT_FAILURE);
290 1.1 gdamore }
291 1.1 gdamore
292 1.1 gdamore if (n == 0)
293 1.1 gdamore continue;
294 1.1 gdamore
295 1.1 gdamore if (FD_ISSET(amaster, &rfd)) {
296 1.1 gdamore n = sppd_read(amaster, buf, sizeof(buf));
297 1.1 gdamore if (n < 0) {
298 1.1 gdamore syslog(LOG_ERR, "Could not read master pty, "
299 1.1 gdamore "fd=%d. %s", amaster, strerror(errno));
300 1.1 gdamore exit(EXIT_FAILURE);
301 1.1 gdamore }
302 1.1 gdamore
303 1.1 gdamore if (n == 0)
304 1.1 gdamore break; /* XXX */
305 1.1 gdamore
306 1.1 gdamore if (sppd_write(s, buf, (size_t)n) < 0) {
307 1.1 gdamore syslog(LOG_ERR, "Could not write to socket, "
308 1.1 gdamore "fd=%d, size=%d. %s",
309 1.1 gdamore s, n, strerror(errno));
310 1.1 gdamore exit(EXIT_FAILURE);
311 1.1 gdamore }
312 1.1 gdamore }
313 1.1 gdamore
314 1.1 gdamore if (FD_ISSET(s, &rfd)) {
315 1.1 gdamore n = sppd_read(s, buf, sizeof(buf));
316 1.1 gdamore if (n < 0) {
317 1.1 gdamore syslog(LOG_ERR, "Could not read socket, " \
318 1.1 gdamore "fd=%d. %s", s, strerror(errno));
319 1.1 gdamore exit(EXIT_FAILURE);
320 1.1 gdamore }
321 1.1 gdamore
322 1.1 gdamore if (n == 0)
323 1.1 gdamore break;
324 1.1 gdamore
325 1.1 gdamore if (sppd_write(fd, buf, (size_t)n) < 0) {
326 1.1 gdamore syslog(LOG_ERR, "Could not write to master " \
327 1.1 gdamore "pty, fd=%d, size=%d. %s",
328 1.1 gdamore fd, n, strerror(errno));
329 1.1 gdamore exit(EXIT_FAILURE);
330 1.1 gdamore }
331 1.1 gdamore }
332 1.1 gdamore }
333 1.1 gdamore
334 1.1 gdamore syslog(LOG_INFO, "Completed on %s", (tty != NULL)? tty : "stdin/stdout");
335 1.1 gdamore closelog();
336 1.1 gdamore
337 1.1 gdamore close(s);
338 1.1 gdamore
339 1.1 gdamore if (tty != NULL) {
340 1.1 gdamore close(aslave);
341 1.1 gdamore close(amaster);
342 1.1 gdamore }
343 1.1 gdamore
344 1.1 gdamore return (0);
345 1.1 gdamore }
346 1.1 gdamore
347 1.1 gdamore /* Open TTYs */
348 1.1 gdamore static int
349 1.1 gdamore sppd_ttys_open(char const *tty, int *amaster, int *aslave)
350 1.1 gdamore {
351 1.1 gdamore char pty[PATH_MAX], *slash;
352 1.1 gdamore struct group *gr = NULL;
353 1.1 gdamore gid_t ttygid;
354 1.1 gdamore struct termios tio;
355 1.1 gdamore
356 1.1 gdamore /*
357 1.1 gdamore * Construct master PTY name. The slave tty name must be less then
358 1.1 gdamore * PATH_MAX characters in length, must contain '/' character and
359 1.1 gdamore * must not end with '/'.
360 1.1 gdamore */
361 1.1 gdamore
362 1.1 gdamore if (strlen(tty) >= sizeof(pty)) {
363 1.1 gdamore syslog(LOG_ERR, "Slave tty name is too long");
364 1.1 gdamore return (-1);
365 1.1 gdamore }
366 1.1 gdamore
367 1.1 gdamore strlcpy(pty, tty, sizeof(pty));
368 1.1 gdamore slash = strrchr(pty, '/');
369 1.1 gdamore if (slash == NULL || slash[1] == '\0') {
370 1.1 gdamore syslog(LOG_ERR, "Invalid slave tty name (%s)", tty);
371 1.1 gdamore return (-1);
372 1.1 gdamore }
373 1.1 gdamore
374 1.1 gdamore slash[1] = 'p';
375 1.1 gdamore
376 1.1 gdamore if (strcmp(pty, tty) == 0) {
377 1.1 gdamore syslog(LOG_ERR, "Master and slave tty are the same (%s)", tty);
378 1.1 gdamore return (-1);
379 1.1 gdamore }
380 1.1 gdamore
381 1.1 gdamore if ((*amaster = open(pty, O_RDWR, 0)) < 0) {
382 1.1 gdamore syslog(LOG_ERR, "Could not open(%s). %s", pty, strerror(errno));
383 1.1 gdamore return (-1);
384 1.1 gdamore }
385 1.1 gdamore
386 1.1 gdamore /*
387 1.1 gdamore * Slave TTY
388 1.1 gdamore */
389 1.1 gdamore
390 1.1 gdamore if ((gr = getgrnam("tty")) != NULL)
391 1.1 gdamore ttygid = gr->gr_gid;
392 1.1 gdamore else
393 1.1 gdamore ttygid = (gid_t)-1;
394 1.1 gdamore
395 1.1 gdamore (void) chown(tty, getuid(), ttygid);
396 1.1 gdamore (void) chmod(tty, S_IRUSR|S_IWUSR|S_IWGRP);
397 1.1 gdamore (void) revoke(tty);
398 1.1 gdamore
399 1.1 gdamore if ((*aslave = open(tty, O_RDWR, 0)) < 0) {
400 1.1 gdamore syslog(LOG_ERR, "Could not open(%s). %s", tty, strerror(errno));
401 1.1 gdamore close(*amaster);
402 1.1 gdamore return (-1);
403 1.1 gdamore }
404 1.1 gdamore
405 1.1 gdamore /*
406 1.1 gdamore * Make slave TTY raw
407 1.1 gdamore */
408 1.1 gdamore
409 1.1 gdamore cfmakeraw(&tio);
410 1.1 gdamore
411 1.1 gdamore if (tcsetattr(*aslave, TCSANOW, &tio) < 0) {
412 1.1 gdamore syslog(LOG_ERR, "Could not tcsetattr(). %s", strerror(errno));
413 1.1 gdamore close(*aslave);
414 1.1 gdamore close(*amaster);
415 1.1 gdamore return (-1);
416 1.1 gdamore }
417 1.1 gdamore
418 1.1 gdamore return (0);
419 1.1 gdamore } /* sppd_ttys_open */
420 1.1 gdamore
421 1.1 gdamore /* Read data */
422 1.1 gdamore static int
423 1.1 gdamore sppd_read(int fd, char *buffer, size_t size)
424 1.1 gdamore {
425 1.1 gdamore int n;
426 1.1 gdamore
427 1.1 gdamore again:
428 1.1 gdamore n = read(fd, buffer, size);
429 1.1 gdamore if (n < 0) {
430 1.1 gdamore if (errno == EINTR)
431 1.1 gdamore goto again;
432 1.1 gdamore
433 1.1 gdamore return (-1);
434 1.1 gdamore }
435 1.1 gdamore
436 1.1 gdamore return (n);
437 1.1 gdamore } /* sppd_read */
438 1.1 gdamore
439 1.1 gdamore /* Write data */
440 1.1 gdamore static int
441 1.1 gdamore sppd_write(int fd, char *buffer, size_t size)
442 1.1 gdamore {
443 1.1 gdamore int n, wrote;
444 1.1 gdamore
445 1.1 gdamore for (wrote = 0; size > 0; ) {
446 1.1 gdamore n = write(fd, buffer, size);
447 1.1 gdamore switch (n) {
448 1.1 gdamore case -1:
449 1.1 gdamore if (errno != EINTR)
450 1.1 gdamore return (-1);
451 1.1 gdamore break;
452 1.1 gdamore
453 1.1 gdamore case 0:
454 1.1 gdamore /* XXX can happen? */
455 1.1 gdamore break;
456 1.1 gdamore
457 1.1 gdamore default:
458 1.1 gdamore wrote += n;
459 1.1 gdamore buffer += n;
460 1.1 gdamore size -= n;
461 1.1 gdamore break;
462 1.1 gdamore }
463 1.1 gdamore }
464 1.1 gdamore
465 1.1 gdamore return (wrote);
466 1.1 gdamore } /* sppd_write */
467 1.1 gdamore
468 1.1 gdamore /* Signal handler */
469 1.1 gdamore static void
470 1.1 gdamore sppd_sighandler(int s)
471 1.1 gdamore {
472 1.1 gdamore syslog(LOG_INFO, "Signal %d received. Total %d signals received\n",
473 1.1 gdamore s, ++ done);
474 1.1 gdamore } /* sppd_sighandler */
475 1.1 gdamore
476 1.1 gdamore /* Display usage and exit */
477 1.1 gdamore static void
478 1.1 gdamore usage(void)
479 1.1 gdamore {
480 1.1 gdamore fprintf(stdout,
481 1.1 gdamore "Usage: %s options\n" \
482 1.1 gdamore "Where options are:\n" \
483 1.1 gdamore "\t-a address Address to connect to (required)\n" \
484 1.1 gdamore "\t-b Run in background\n" \
485 1.1 gdamore "\t-c channel RFCOMM channel to connect to\n" \
486 1.1 gdamore "\t-d device Device to connect from\n" \
487 1.1 gdamore "\t-t tty TTY name (required in background mode)\n" \
488 1.1 gdamore "\t-h Display this message\n", SPPD_IDENT);
489 1.1 gdamore
490 1.1 gdamore exit(EXIT_FAILURE);
491 1.1 gdamore } /* usage */
492