16490c2ffSMaksim Yevmenkin /*
26490c2ffSMaksim Yevmenkin * bthidd.c
37aebfa93SMaksim Yevmenkin */
47aebfa93SMaksim Yevmenkin
57aebfa93SMaksim Yevmenkin /*-
6*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
71de7b4b8SPedro F. Giffuni *
87aebfa93SMaksim Yevmenkin * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
96490c2ffSMaksim Yevmenkin * All rights reserved.
106490c2ffSMaksim Yevmenkin *
116490c2ffSMaksim Yevmenkin * Redistribution and use in source and binary forms, with or without
126490c2ffSMaksim Yevmenkin * modification, are permitted provided that the following conditions
136490c2ffSMaksim Yevmenkin * are met:
146490c2ffSMaksim Yevmenkin * 1. Redistributions of source code must retain the above copyright
156490c2ffSMaksim Yevmenkin * notice, this list of conditions and the following disclaimer.
166490c2ffSMaksim Yevmenkin * 2. Redistributions in binary form must reproduce the above copyright
176490c2ffSMaksim Yevmenkin * notice, this list of conditions and the following disclaimer in the
186490c2ffSMaksim Yevmenkin * documentation and/or other materials provided with the distribution.
196490c2ffSMaksim Yevmenkin *
206490c2ffSMaksim Yevmenkin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
216490c2ffSMaksim Yevmenkin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
226490c2ffSMaksim Yevmenkin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
236490c2ffSMaksim Yevmenkin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
246490c2ffSMaksim Yevmenkin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
256490c2ffSMaksim Yevmenkin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
266490c2ffSMaksim Yevmenkin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
276490c2ffSMaksim Yevmenkin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
286490c2ffSMaksim Yevmenkin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
296490c2ffSMaksim Yevmenkin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
306490c2ffSMaksim Yevmenkin * SUCH DAMAGE.
316490c2ffSMaksim Yevmenkin *
327aebfa93SMaksim Yevmenkin * $Id: bthidd.c,v 1.8 2006/09/07 21:06:53 max Exp $
336490c2ffSMaksim Yevmenkin */
346490c2ffSMaksim Yevmenkin
356490c2ffSMaksim Yevmenkin #include <sys/time.h>
366490c2ffSMaksim Yevmenkin #include <sys/queue.h>
376490c2ffSMaksim Yevmenkin #include <assert.h>
388d6f425dSTakanori Watanabe #define L2CAP_SOCKET_CHECKED
396490c2ffSMaksim Yevmenkin #include <bluetooth.h>
406490c2ffSMaksim Yevmenkin #include <err.h>
416490c2ffSMaksim Yevmenkin #include <errno.h>
426490c2ffSMaksim Yevmenkin #include <signal.h>
436490c2ffSMaksim Yevmenkin #include <stdio.h>
446490c2ffSMaksim Yevmenkin #include <stdlib.h>
456490c2ffSMaksim Yevmenkin #include <string.h>
466490c2ffSMaksim Yevmenkin #include <syslog.h>
476490c2ffSMaksim Yevmenkin #include <unistd.h>
486490c2ffSMaksim Yevmenkin #include <usbhid.h>
496490c2ffSMaksim Yevmenkin #include "bthid_config.h"
507aebfa93SMaksim Yevmenkin #include "bthidd.h"
516490c2ffSMaksim Yevmenkin
527aebfa93SMaksim Yevmenkin static int32_t write_pid_file (char const *file);
537aebfa93SMaksim Yevmenkin static int32_t remove_pid_file (char const *file);
547aebfa93SMaksim Yevmenkin static int32_t elapsed (int32_t tval);
557aebfa93SMaksim Yevmenkin static void sighandler (int32_t s);
566490c2ffSMaksim Yevmenkin static void usage (void);
576490c2ffSMaksim Yevmenkin
586490c2ffSMaksim Yevmenkin /*
596490c2ffSMaksim Yevmenkin * bthidd
606490c2ffSMaksim Yevmenkin */
616490c2ffSMaksim Yevmenkin
627aebfa93SMaksim Yevmenkin static int32_t done = 0; /* are we done? */
636490c2ffSMaksim Yevmenkin
647aebfa93SMaksim Yevmenkin int32_t
main(int32_t argc,char * argv[])657aebfa93SMaksim Yevmenkin main(int32_t argc, char *argv[])
666490c2ffSMaksim Yevmenkin {
676490c2ffSMaksim Yevmenkin struct bthid_server srv;
686490c2ffSMaksim Yevmenkin struct sigaction sa;
697aebfa93SMaksim Yevmenkin char const *pid_file = BTHIDD_PIDFILE;
707aebfa93SMaksim Yevmenkin char *ep;
7144af5666SVladimir Kondratyev int32_t opt, detach, tval, uinput;
726490c2ffSMaksim Yevmenkin
733adfd74aSMaksim Yevmenkin memset(&srv, 0, sizeof(srv));
747aebfa93SMaksim Yevmenkin memset(&srv.bdaddr, 0, sizeof(srv.bdaddr));
756490c2ffSMaksim Yevmenkin detach = 1;
766490c2ffSMaksim Yevmenkin tval = 10; /* sec */
7744af5666SVladimir Kondratyev uinput = 0;
786490c2ffSMaksim Yevmenkin
7944af5666SVladimir Kondratyev while ((opt = getopt(argc, argv, "a:c:dH:hp:t:u")) != -1) {
806490c2ffSMaksim Yevmenkin switch (opt) {
816490c2ffSMaksim Yevmenkin case 'a': /* BDADDR */
826490c2ffSMaksim Yevmenkin if (!bt_aton(optarg, &srv.bdaddr)) {
837aebfa93SMaksim Yevmenkin struct hostent *he;
846490c2ffSMaksim Yevmenkin
856490c2ffSMaksim Yevmenkin if ((he = bt_gethostbyname(optarg)) == NULL)
866490c2ffSMaksim Yevmenkin errx(1, "%s: %s", optarg, hstrerror(h_errno));
876490c2ffSMaksim Yevmenkin
886490c2ffSMaksim Yevmenkin memcpy(&srv.bdaddr, he->h_addr, sizeof(srv.bdaddr));
896490c2ffSMaksim Yevmenkin }
906490c2ffSMaksim Yevmenkin break;
916490c2ffSMaksim Yevmenkin
926490c2ffSMaksim Yevmenkin case 'c': /* config file */
936490c2ffSMaksim Yevmenkin config_file = optarg;
946490c2ffSMaksim Yevmenkin break;
956490c2ffSMaksim Yevmenkin
966490c2ffSMaksim Yevmenkin case 'd': /* do not detach */
976490c2ffSMaksim Yevmenkin detach = 0;
986490c2ffSMaksim Yevmenkin break;
996490c2ffSMaksim Yevmenkin
1006490c2ffSMaksim Yevmenkin case 'H': /* hids file */
1016490c2ffSMaksim Yevmenkin hids_file = optarg;
1026490c2ffSMaksim Yevmenkin break;
1036490c2ffSMaksim Yevmenkin
1046490c2ffSMaksim Yevmenkin case 'p': /* pid file */
1056490c2ffSMaksim Yevmenkin pid_file = optarg;
1066490c2ffSMaksim Yevmenkin break;
1076490c2ffSMaksim Yevmenkin
1083adfd74aSMaksim Yevmenkin case 't': /* rescan interval */
1093adfd74aSMaksim Yevmenkin tval = strtol(optarg, (char **) &ep, 10);
1106490c2ffSMaksim Yevmenkin if (*ep != '\0' || tval <= 0)
1116490c2ffSMaksim Yevmenkin usage();
1123adfd74aSMaksim Yevmenkin break;
1133adfd74aSMaksim Yevmenkin
11444af5666SVladimir Kondratyev case 'u': /* enable evdev support */
11544af5666SVladimir Kondratyev uinput = 1;
11644af5666SVladimir Kondratyev break;
11744af5666SVladimir Kondratyev
1186490c2ffSMaksim Yevmenkin case 'h':
1196490c2ffSMaksim Yevmenkin default:
1206490c2ffSMaksim Yevmenkin usage();
1216490c2ffSMaksim Yevmenkin /* NOT REACHED */
1226490c2ffSMaksim Yevmenkin }
1236490c2ffSMaksim Yevmenkin }
1246490c2ffSMaksim Yevmenkin
1256490c2ffSMaksim Yevmenkin openlog(BTHIDD_IDENT, LOG_PID|LOG_PERROR|LOG_NDELAY, LOG_USER);
1266490c2ffSMaksim Yevmenkin
1276490c2ffSMaksim Yevmenkin /* Become daemon if required */
1286490c2ffSMaksim Yevmenkin if (detach && daemon(0, 0) < 0) {
1296490c2ffSMaksim Yevmenkin syslog(LOG_CRIT, "Could not become daemon. %s (%d)",
1306490c2ffSMaksim Yevmenkin strerror(errno), errno);
1316490c2ffSMaksim Yevmenkin exit(1);
1326490c2ffSMaksim Yevmenkin }
1336490c2ffSMaksim Yevmenkin
1346490c2ffSMaksim Yevmenkin /* Install signal handler */
1356490c2ffSMaksim Yevmenkin memset(&sa, 0, sizeof(sa));
1366490c2ffSMaksim Yevmenkin sa.sa_handler = sighandler;
1376490c2ffSMaksim Yevmenkin
1386490c2ffSMaksim Yevmenkin if (sigaction(SIGTERM, &sa, NULL) < 0 ||
1397aebfa93SMaksim Yevmenkin sigaction(SIGHUP, &sa, NULL) < 0 ||
1406490c2ffSMaksim Yevmenkin sigaction(SIGINT, &sa, NULL) < 0) {
1416490c2ffSMaksim Yevmenkin syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)",
1426490c2ffSMaksim Yevmenkin strerror(errno), errno);
1436490c2ffSMaksim Yevmenkin exit(1);
1446490c2ffSMaksim Yevmenkin }
1456490c2ffSMaksim Yevmenkin
1466490c2ffSMaksim Yevmenkin sa.sa_handler = SIG_IGN;
1476490c2ffSMaksim Yevmenkin if (sigaction(SIGPIPE, &sa, NULL) < 0) {
1486490c2ffSMaksim Yevmenkin syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)",
1496490c2ffSMaksim Yevmenkin strerror(errno), errno);
1506490c2ffSMaksim Yevmenkin exit(1);
1516490c2ffSMaksim Yevmenkin }
1526490c2ffSMaksim Yevmenkin
1533adfd74aSMaksim Yevmenkin sa.sa_handler = SIG_IGN;
1543adfd74aSMaksim Yevmenkin sa.sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT;
1553adfd74aSMaksim Yevmenkin if (sigaction(SIGCHLD, &sa, NULL) < 0) {
1563adfd74aSMaksim Yevmenkin syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)",
1573adfd74aSMaksim Yevmenkin strerror(errno), errno);
1583adfd74aSMaksim Yevmenkin exit(1);
1593adfd74aSMaksim Yevmenkin }
1603adfd74aSMaksim Yevmenkin
1616490c2ffSMaksim Yevmenkin if (read_config_file() < 0 || read_hids_file() < 0 ||
1626490c2ffSMaksim Yevmenkin server_init(&srv) < 0 || write_pid_file(pid_file) < 0)
1636490c2ffSMaksim Yevmenkin exit(1);
1646490c2ffSMaksim Yevmenkin
16544af5666SVladimir Kondratyev srv.uinput = uinput;
16644af5666SVladimir Kondratyev
1676490c2ffSMaksim Yevmenkin for (done = 0; !done; ) {
1686490c2ffSMaksim Yevmenkin if (elapsed(tval))
1696490c2ffSMaksim Yevmenkin client_rescan(&srv);
1706490c2ffSMaksim Yevmenkin
1716490c2ffSMaksim Yevmenkin if (server_do(&srv) < 0)
1726490c2ffSMaksim Yevmenkin break;
1736490c2ffSMaksim Yevmenkin }
1746490c2ffSMaksim Yevmenkin
1756490c2ffSMaksim Yevmenkin server_shutdown(&srv);
1766490c2ffSMaksim Yevmenkin remove_pid_file(pid_file);
1776490c2ffSMaksim Yevmenkin clean_config();
1786490c2ffSMaksim Yevmenkin closelog();
1796490c2ffSMaksim Yevmenkin
1806490c2ffSMaksim Yevmenkin return (0);
1816490c2ffSMaksim Yevmenkin }
1826490c2ffSMaksim Yevmenkin
1836490c2ffSMaksim Yevmenkin /*
1846490c2ffSMaksim Yevmenkin * Write pid file
1856490c2ffSMaksim Yevmenkin */
1866490c2ffSMaksim Yevmenkin
1877aebfa93SMaksim Yevmenkin static int32_t
write_pid_file(char const * file)1886490c2ffSMaksim Yevmenkin write_pid_file(char const *file)
1896490c2ffSMaksim Yevmenkin {
1907aebfa93SMaksim Yevmenkin FILE *pid;
1916490c2ffSMaksim Yevmenkin
1926490c2ffSMaksim Yevmenkin assert(file != NULL);
1936490c2ffSMaksim Yevmenkin
1946490c2ffSMaksim Yevmenkin if ((pid = fopen(file, "w")) == NULL) {
1956490c2ffSMaksim Yevmenkin syslog(LOG_ERR, "Could not open file %s. %s (%d)",
1966490c2ffSMaksim Yevmenkin file, strerror(errno), errno);
1976490c2ffSMaksim Yevmenkin return (-1);
1986490c2ffSMaksim Yevmenkin }
1996490c2ffSMaksim Yevmenkin
2006490c2ffSMaksim Yevmenkin fprintf(pid, "%d", getpid());
2016490c2ffSMaksim Yevmenkin fclose(pid);
2026490c2ffSMaksim Yevmenkin
2036490c2ffSMaksim Yevmenkin return (0);
2046490c2ffSMaksim Yevmenkin }
2056490c2ffSMaksim Yevmenkin
2066490c2ffSMaksim Yevmenkin /*
2076490c2ffSMaksim Yevmenkin * Remote pid file
2086490c2ffSMaksim Yevmenkin */
2096490c2ffSMaksim Yevmenkin
2107aebfa93SMaksim Yevmenkin static int32_t
remove_pid_file(char const * file)2116490c2ffSMaksim Yevmenkin remove_pid_file(char const *file)
2126490c2ffSMaksim Yevmenkin {
2136490c2ffSMaksim Yevmenkin assert(file != NULL);
2146490c2ffSMaksim Yevmenkin
2156490c2ffSMaksim Yevmenkin if (unlink(file) < 0) {
2166490c2ffSMaksim Yevmenkin syslog(LOG_ERR, "Could not unlink file %s. %s (%d)",
2176490c2ffSMaksim Yevmenkin file, strerror(errno), errno);
2186490c2ffSMaksim Yevmenkin return (-1);
2196490c2ffSMaksim Yevmenkin }
2206490c2ffSMaksim Yevmenkin
2216490c2ffSMaksim Yevmenkin return (0);
2226490c2ffSMaksim Yevmenkin }
2236490c2ffSMaksim Yevmenkin
2246490c2ffSMaksim Yevmenkin /*
2256490c2ffSMaksim Yevmenkin * Returns true if desired time interval has elapsed
2266490c2ffSMaksim Yevmenkin */
2276490c2ffSMaksim Yevmenkin
2287aebfa93SMaksim Yevmenkin static int32_t
elapsed(int32_t tval)2297aebfa93SMaksim Yevmenkin elapsed(int32_t tval)
2306490c2ffSMaksim Yevmenkin {
2317aebfa93SMaksim Yevmenkin static struct timeval last = { 0, 0 };
2326490c2ffSMaksim Yevmenkin struct timeval now;
2336490c2ffSMaksim Yevmenkin
2346490c2ffSMaksim Yevmenkin gettimeofday(&now, NULL);
2356490c2ffSMaksim Yevmenkin
2366490c2ffSMaksim Yevmenkin if (now.tv_sec - last.tv_sec >= tval) {
2376490c2ffSMaksim Yevmenkin last = now;
2386490c2ffSMaksim Yevmenkin return (1);
2396490c2ffSMaksim Yevmenkin }
2406490c2ffSMaksim Yevmenkin
2416490c2ffSMaksim Yevmenkin return (0);
2426490c2ffSMaksim Yevmenkin }
2436490c2ffSMaksim Yevmenkin
2446490c2ffSMaksim Yevmenkin /*
2457aebfa93SMaksim Yevmenkin * Signal handler
2466490c2ffSMaksim Yevmenkin */
2476490c2ffSMaksim Yevmenkin
2486490c2ffSMaksim Yevmenkin static void
sighandler(int32_t s)2497aebfa93SMaksim Yevmenkin sighandler(int32_t s)
2506490c2ffSMaksim Yevmenkin {
2516490c2ffSMaksim Yevmenkin syslog(LOG_NOTICE, "Got signal %d, total number of signals %d",
2526490c2ffSMaksim Yevmenkin s, ++ done);
2536490c2ffSMaksim Yevmenkin }
2546490c2ffSMaksim Yevmenkin
2556490c2ffSMaksim Yevmenkin /*
2566490c2ffSMaksim Yevmenkin * Display usage and exit
2576490c2ffSMaksim Yevmenkin */
2586490c2ffSMaksim Yevmenkin
2596490c2ffSMaksim Yevmenkin static void
usage(void)2606490c2ffSMaksim Yevmenkin usage(void)
2616490c2ffSMaksim Yevmenkin {
2626490c2ffSMaksim Yevmenkin fprintf(stderr,
2636490c2ffSMaksim Yevmenkin "Usage: %s [options]\n" \
2646490c2ffSMaksim Yevmenkin "Where options are:\n" \
2652aa65cf7SMaksim Yevmenkin " -a address specify address to listen on (default ANY)\n" \
2666490c2ffSMaksim Yevmenkin " -c file specify config file name\n" \
2676490c2ffSMaksim Yevmenkin " -d run in foreground\n" \
2686490c2ffSMaksim Yevmenkin " -H file specify known HIDs file name\n" \
2696490c2ffSMaksim Yevmenkin " -h display this message\n" \
2706490c2ffSMaksim Yevmenkin " -p file specify PID file name\n" \
2713adfd74aSMaksim Yevmenkin " -t tval specify client rescan interval (sec)\n" \
27244af5666SVladimir Kondratyev " -u enable evdev protocol support\n" \
2736490c2ffSMaksim Yevmenkin "", BTHIDD_IDENT);
2746490c2ffSMaksim Yevmenkin exit(255);
2756490c2ffSMaksim Yevmenkin }
2766490c2ffSMaksim Yevmenkin
277