Home | History | Annotate | Line # | Download | only in rfcomm_sppd
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