this repo has no description
1/*
2 * $Id: blueping.c,v 1.8 2005/12/18 03:31:46 jcs Exp $
3 *
4 * blueping
5 * a bluetooth monitoring utility
6 *
7 * Copyright (c) 2005 joshua stein <jcs@jcs.org>
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_2
34
35#include <CoreFoundation/CoreFoundation.h>
36#include <IOBluetooth/IOBluetoothUserLib.h>
37#include <IOBluetooth/IOBluetoothUtilities.h>
38#include <err.h>
39#include <signal.h>
40#include <time.h>
41
42void bail(int);
43void dolog(char *);
44void launchapp(char *);
45void pingloop(void);
46void sig_handler(int);
47void usage(void);
48
49IOBluetoothDeviceRef device;
50CFRunLoopTimerRef looptimer;
51char enterprog[1024], exitprog[1024];
52int connected = -1;
53int verbose = 0;
54
55/* default poll interval in seconds */
56long pollint = 15;
57
58extern char *__progname;
59
60int
61main(int argc, char *argv[])
62{
63 BluetoothDeviceAddress device_address;
64 CFStringRef t;
65 char macbuf[255], logstr[255];
66 char *inval = NULL, *self = NULL, *p = NULL;
67 u_char devname[50];
68 int ch;
69
70 CFRunLoopTimerContext context = {0, self, NULL, NULL, NULL};
71
72 bzero(enterprog, sizeof(enterprog));
73 bzero(exitprog, sizeof(exitprog));
74 bzero(macbuf, sizeof(macbuf));
75
76 while ((ch = getopt(argc, argv, "d:e:i:vx:")) != -1) {
77 switch (ch) {
78 case 'd':
79 strncpy(macbuf, optarg, sizeof(macbuf));
80 break;
81 case 'e':
82 strncpy(enterprog, optarg, sizeof(enterprog));
83 break;
84 case 'i':
85 if ((!(pollint = strtol((p = optarg), &inval, 10))) ||
86 (pollint < 1))
87 errx(1, "invalid poll interval -- %s", optarg);
88 break;
89 case 'v':
90 verbose++;
91 break;
92 case 'x':
93 strncpy(exitprog, optarg, sizeof(exitprog));
94 break;
95 default:
96 usage();
97 }
98 }
99
100 if (!strlen(macbuf))
101 usage();
102
103 if (!IOBluetoothLocalDeviceAvailable()) {
104 fprintf(stderr, "%s: no bluetooth available\n", __progname);
105 exit(1);
106 }
107
108 signal(SIGCHLD, sig_handler);
109 signal(SIGINT, sig_handler);
110
111 /* convert the mac address and establish our object */
112 t = CFStringCreateWithCString(NULL, macbuf, kCFStringEncodingASCII);
113 int status = IOBluetoothNSStringToDeviceAddress(t, &device_address);
114 if (status != kIOReturnSuccess) {
115 fprintf(stderr, "%s: error creating device address: %s\n",
116 __progname, macbuf);
117 exit(1);
118 }
119 CFRelease(t);
120
121 device = IOBluetoothDeviceCreateWithAddress(&device_address);
122
123 if (verbose) {
124 status = IOBluetoothDeviceRemoteNameRequest(device, NULL, NULL,
125 devname);
126 if (status == kIOReturnSuccess) {
127 snprintf(logstr, sizeof(logstr),
128 "found device named \"%s\"", devname);
129 dolog(logstr);
130 }
131 }
132
133 looptimer = CFRunLoopTimerCreate(
134 NULL,
135 CFAbsoluteTimeGetCurrent(),
136 pollint,
137 0,
138 0,
139 (void *)pingloop,
140 &context);
141
142 CFRunLoopAddTimer(CFRunLoopGetCurrent(), looptimer,
143 kCFRunLoopCommonModes);
144
145 CFRunLoopRun();
146
147 IOBluetoothDeviceCloseConnection(device);
148 IOBluetoothObjectRelease(device);
149
150 return(0);
151}
152
153void
154usage()
155{
156 fprintf(stderr, "usage: %s -d macaddr [-e enterprog] [-i pollint] [-v]"
157 " [-x exitprog]\n", __progname);
158 exit(1);
159}
160
161void
162dolog(char *entry)
163{
164 struct timeval tv[2];
165 time_t now;
166 struct tm *tm;
167
168 gettimeofday(&tv[0], NULL);
169 now = tv[0].tv_sec;
170 tm = localtime(&now);
171
172 printf("[%02d:%02d:%02d] %s\n", tm->tm_hour, tm->tm_min, tm->tm_sec,
173 entry);
174}
175
176void
177pingloop()
178{
179 int status;
180 char logstr[512];
181
182 status = IOBluetoothDeviceOpenConnection(device, NULL, NULL);
183 if (status == kIOReturnSuccess) {
184 if (connected == 0 && verbose) {
185 bzero(logstr, sizeof(logstr));
186 snprintf(logstr, sizeof(logstr),
187 "device entered range");
188
189 if (strlen(enterprog))
190 snprintf(logstr, sizeof(logstr),
191 "%s, executing \"%s\"", logstr,
192 enterprog);
193
194 dolog(logstr);
195 }
196
197 if (connected == 0 && strlen(enterprog))
198 launchapp(enterprog);
199
200 connected = 1;
201 } else {
202 if (connected == 1 && verbose) {
203 bzero(logstr, sizeof(logstr));
204 snprintf(logstr, sizeof(logstr), "device left range");
205
206 if (strlen(exitprog))
207 snprintf(logstr, sizeof(logstr),
208 "%s, executing \"%s\"", logstr,
209 exitprog);
210
211 dolog(logstr);
212 }
213
214 if (connected == 1 && strlen(exitprog))
215 launchapp(exitprog);
216
217 connected = 0;
218 }
219
220 IOBluetoothDeviceCloseConnection(device);
221
222 if (verbose > 1) {
223 bzero(logstr, sizeof(logstr));
224 snprintf(logstr, sizeof(logstr), "device is %sin range, "
225 "sleeping for %ld second%s",
226 (connected == 1 ? "" : "not "), pollint,
227 (pollint == 1 ? "" : "s"));
228 dolog(logstr);
229 }
230}
231
232void
233launchapp(char *progname)
234{
235 char *argp[] = {"sh", "-c", NULL, NULL};
236 pid_t pid;
237
238 argp[2] = progname;
239 pid = fork();
240 if (pid == 0) {
241 execv("/bin/sh", argp);
242 _exit(1);
243 }
244}
245
246void
247sig_handler(int sig)
248{
249 switch (sig) {
250 case SIGCHLD:
251 printf("got sigchld\n");
252 wait(NULL);
253 break;
254 case SIGINT:
255 printf("\nshutting down\n");
256 IOBluetoothDeviceCloseConnection(device);
257 IOBluetoothObjectRelease(device);
258 _exit(0);
259 break;
260 }
261}