View | Details | Raw Unified | Return to bug 196678 | Differences between
and this patch

Collapse All | Expand All

(-)config/devd.c (+683 lines)
Line 0 Link Here
1
/*
2
 * Copyright (c) 2012 Baptiste Daroussin
3
 * Copyright (c) 2013, 2014 Alex Kozlov
4
 * Copyright (c) 2014 Robert Millan
5
 * Copyright (c) 2014 Jean-Sebastien Pedron
6
 * Copyright (c) 2015-2016 Rozhuk Ivan
7
 *
8
 * Permission is hereby granted, free of charge, to any person obtaining a
9
 * copy of this software and associated documentation files (the "Software"),
10
 * to deal in the Software without restriction, including without limitation
11
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12
 * and/or sell copies of the Software, and to permit persons to whom the
13
 * Software is furnished to do so, subject to the following conditions:
14
 *
15
 * The above copyright notice and this permission notice (including the next
16
 * paragraph) shall be included in all copies or substantial portions of the
17
 * Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25
 * DEALINGS IN THE SOFTWARE.
26
 *
27
 * Author: Baptiste Daroussin <bapt@FreeBSD.org>
28
 */
29
30
#ifdef HAVE_DIX_CONFIG_H
31
#include <dix-config.h>
32
#endif
33
34
#include <sys/types.h>
35
#include <sys/kbio.h>
36
#include <sys/socket.h>
37
#include <sys/stat.h>
38
#include <sys/sysctl.h>
39
#include <sys/un.h>
40
#include <sys/mouse.h>
41
#include <sys/consio.h>
42
#include <linux/input.h>
43
44
#include <ctype.h>
45
#include <dirent.h>
46
#include <errno.h>
47
#include <fcntl.h>
48
#include <stdlib.h>
49
#include <stdio.h>
50
#include <stdbool.h>
51
#include <unistd.h>
52
#include <string.h>
53
#include <paths.h>
54
55
#include "input.h"
56
#include "inputstr.h"
57
#include "hotplug.h"
58
#include "config-backends.h"
59
#include "os.h"
60
61
62
/* from <linux/joystick.h> */
63
/* get identifier string */
64
#define JSIOCGNAME(len)		_IOC(_IOC_READ, 'j', 0x13, len)
65
66
#define WEBCAMD_IOCTL_GET_USB_VENDOR_ID _IOR('q', 250, unsigned short)
67
#define WEBCAMD_IOCTL_GET_USB_PRODUCT_ID _IOR('q', 251, unsigned short)
68
#define WEBCAMD_IOCTL_GET_USB_SPEED	_IOR('q', 252, unsigned int)
69
70
71
#define _PATH_DEV_LEN		(sizeof(_PATH_DEV) - 1)
72
#define DEVD_PATH_DEV		"devd:" _PATH_DEV
73
#define DEVD_PATH_DEV_LEN	(sizeof(DEVD_PATH_DEV) - 1)
74
75
#define DEVD_SOCK_PATH		_PATH_VARRUN "devd.pipe"
76
77
#define DEVD_EVENT_ADD		'+'
78
#define DEVD_EVENT_REMOVE	'-'
79
#define DEVD_EVENT_NOTIFY	'!'
80
81
#define RECONNECT_DELAY		(5 * 1000)
82
83
84
#define is_meuqual(__v1, __v1sz, __v2, __v2sz)				\
85
	((__v1sz) == (__v2sz) && NULL != (__v1) && NULL != (__v2) &&	\
86
	 0 == memcmp((__v1), (__v2), (__v1sz)))
87
#define is_de_euqual(__de, __v, __vsz)					\
88
	(NULL != (__de) &&						\
89
	 is_meuqual((__de)->d_name, (__de)->d_namlen, (__v), (__vsz)))
90
91
92
static int devd_skt;
93
static char devd_buf[4096];
94
static size_t devd_buf_used = 0;
95
static int is_kbdmux = 0;
96
OsTimerPtr rtimer;
97
98
99
/* Input devices. */
100
typedef struct hw_type_s {
101
	const char	*dev_name;
102
	size_t		dev_name_size;
103
	int		flags;
104
	const char	*xdriver; 
105
} hw_type_t, *hw_type_p;
106
107
/* xdriver can be set via config "InputClass" section.
108
 * Do not set xdriver name if device have more than one
109
 * xf86-input-* drivers.
110
 * "input/event" can be hadled by: xf86-input-evdev and
111
 * xf86-input-wacom, let user chooses.
112
 */
113
static hw_type_t hw_types[] = {
114
	{ "ukbd",	4, ATTR_KEYBOARD, "kbd" },
115
	{ "atkbd",	5, ATTR_KEYBOARD, "kbd" },
116
	{ "kbdmux",	6, ATTR_KEYBOARD, "kbd" },
117
	{ "sysmouse",	8, ATTR_POINTER, "mouse" },
118
	{ "ums",	3, ATTR_POINTER, "mouse" },
119
	{ "psm",	3, ATTR_POINTER, "mouse" },
120
	{ "vboxguest",	9, ATTR_POINTER, "vboxmouse" },
121
	{ "joy",	3, ATTR_JOYSTICK, NULL },
122
	{ "atp",	3, ATTR_TOUCHPAD, NULL },
123
	{ "uep",	3, ATTR_TOUCHSCREEN, NULL },
124
	{ "input/event",11, ATTR_TOUCHPAD, NULL },
125
	{ "input/js",	8, ATTR_JOYSTICK, NULL },
126
	{ NULL, 0, 0, NULL },
127
};
128
129
130
static hw_type_p
131
get_dev_type_by_name(const char *dev_name, size_t dev_name_size)
132
{
133
	size_t i;
134
135
	if (NULL == dev_name || 0 == dev_name_size)
136
		return (NULL);
137
	for (i = 0; NULL != hw_types[i].dev_name; i ++) {
138
		if (dev_name_size >= hw_types[i].dev_name_size &&
139
		    0 == memcmp(dev_name, hw_types[i].dev_name, hw_types[i].dev_name_size)) {
140
			return (&hw_types[i]);
141
		}
142
	}
143
	return (NULL);
144
}
145
146
static int
147
is_kbdmux_enabled(void)
148
{
149
	/* Xorg uses /dev/ttyv0 as a console device */
150
	/* const char device[]="/dev/console"; */
151
	int fd;
152
	const char *device = _PATH_TTY "v0";
153
	keyboard_info_t info;
154
155
	fd = open(device, O_RDONLY);
156
	if (fd < 0)
157
		return (0);
158
	if (ioctl(fd, KDGKBINFO, &info) == -1 ||
159
	    0 != memcmp(info.kb_name, "kbdmux", 6)) {
160
		close(fd);
161
		return (0);
162
	}
163
	close(fd);
164
	return (1);
165
}
166
167
static char *
168
sysctl_get_str(const char *sysctlname, size_t *size_ret)
169
{
170
	char *dest;
171
	size_t len;
172
173
	if (NULL == sysctlname)
174
		return (NULL);
175
	if (0 != sysctlbyname(sysctlname, NULL, &len, NULL, 0))
176
		return (NULL);
177
	dest = malloc(len + 4);
178
	if (NULL == dest)
179
		return (NULL);
180
	if (0 != sysctlbyname(sysctlname, dest, &len, NULL, 0)) {
181
		free(dest);
182
		return (NULL);
183
	}
184
	dest[len] = 0;
185
	if (NULL != size_ret)
186
		(*size_ret) = len;
187
	return (dest);
188
}
189
190
static char *
191
devd_get_val(char *buf, size_t buf_size, const char *val_name,
192
    size_t val_name_size, size_t *val_size)
193
{
194
	char *ret, *buf_end, *ptr;
195
196
	buf_end = (buf + buf_size);
197
	for (ret = buf; ret != NULL && ret < buf_end;) {
198
		ret = memmem(ret, (buf_end - ret), val_name, val_name_size);
199
		if (ret == NULL)
200
			return (NULL);
201
		/* Found. */
202
		/* Check: space before or buf+1. */
203
		if ((buf + 1) < ret && ret[-1] != ' ') {
204
			ret += val_name_size;
205
			continue;
206
		}
207
		/* Check: = after name and size for value. */
208
		ret += val_name_size;
209
		if ((ret + 1) >= buf_end)
210
			return (NULL);
211
		if (ret[0] != '=')
212
			continue;
213
		ret ++;
214
		break;
215
	}
216
	if (ret == NULL || val_size == NULL)
217
		return (ret);
218
	/* Calc value data size. */
219
	ptr = memchr(ret, ' ', (buf_end - ret));
220
	if (ptr == NULL) /* End of string/last value. */
221
		ptr = buf_end;
222
	(*val_size) = (ptr - ret);
223
	return (ret);
224
}
225
226
static void
227
device_added(const char *dev_name, size_t dev_name_size, int allow_no_device)
228
{
229
	int fd;
230
	InputOption *options = NULL;
231
	InputAttributes attrs = { };
232
	DeviceIntPtr dev_iptr = NULL;
233
	keyboard_info_t kbdi;
234
	mousehw_t mshw;
235
	struct input_id iid;
236
	char *dev_path, config_info[(PATH_MAX + 32)];
237
	char sysctlname[PATH_MAX], *sdata, *ptr_pid, *ptr_vid;
238
	char pnp_usb_id[PATH_MAX], vendor[PATH_MAX], product[PATH_MAX];
239
	size_t sdata_size, pid_size, vid_size;
240
	hw_type_p hwtype;
241
	unsigned short vid, pid;
242
243
244
	if (NULL == dev_name || 0 == dev_name_size || PATH_MAX < dev_name_size)
245
		return;
246
	/* Is known input device? */
247
	hwtype = get_dev_type_by_name(dev_name, dev_name_size);
248
	if (NULL == hwtype) /* Not found in white list. */
249
		return;
250
	memcpy(config_info, DEVD_PATH_DEV, DEVD_PATH_DEV_LEN);
251
	memcpy((config_info + DEVD_PATH_DEV_LEN), dev_name, dev_name_size);
252
	config_info[(DEVD_PATH_DEV_LEN + dev_name_size)] = 0;
253
	dev_path = (config_info + 5); /* Skip: "devd:" */
254
	dev_name = (dev_path + _PATH_DEV_LEN); /* Skip: "/dev/" */
255
	attrs.device = dev_path;
256
	attrs.flags = hwtype->flags;
257
258
	/* Skip keyboard devices if kbdmux is enabled */
259
	if (is_kbdmux && 0 == allow_no_device && (hwtype->flags & ATTR_KEYBOARD)) {
260
		LogMessage(X_INFO, "config/devd: kbdmux is enabled, ignoring device %s\n",
261
		    dev_name);
262
		return;
263
	}
264
	/* Skip duplicate devices. */
265
	if (device_is_duplicate(config_info)) {
266
		LogMessage(X_WARNING, "config/devd: device %s already added. ignoring\n",
267
		    dev_path);
268
		return;
269
	}
270
271
	/* Try to open device. */
272
	fd = open(dev_path, O_RDONLY);
273
	if (fd < 0) {
274
		if (0 == (hwtype->flags & ATTR_KEYBOARD)) {
275
			LogMessage(X_INFO, "config/devd: device %s already opened\n",
276
			    dev_path);
277
			/*
278
			 * Fail if cannot open device, it breaks AllowMouseOpenFail,
279
			 * but it should not matter when config/devd enabled
280
			 */
281
			return;
282
		}
283
		if (0 == allow_no_device) {
284
			/*
285
			 * There can be only one keyboard attached to console and
286
			 * it is already added.
287
			 */
288
			LogMessage(X_WARNING, "config/devd: console keyboard is "
289
			    "already added, ignoring %s\n",
290
			    dev_path);
291
			return;
292
		}
293
		/*
294
		 * Don't pass "device" option if the keyboard is already
295
		 * attached to the console (ie. open() fails).
296
		 * This would activate a special logic in xf86-input-keyboard.
297
		 * Prevent any other attached to console keyboards being
298
		 * processed. There can be only one such device.
299
		 */
300
		goto skip_ioctl;
301
	}
302
303
	/* Try to get device info via ioctl(). */
304
	if (ioctl(fd, KDGKBINFO, &kbdi) != -1) { /* Is this keyboard? */
305
		memcpy(product, kbdi.kb_name, sizeof(kbdi.kb_name));
306
		attrs.product = product;
307
		attrs.flags = ATTR_KEYBOARD;
308
		LogMessage(X_INFO, "config/devd: detected keyboard: %s, kb_index=%i, kb_unit=%i, kb_type=%i, kb_config=%i\n",
309
		    kbdi.kb_name, kbdi.kb_index, kbdi.kb_unit, kbdi.kb_type, kbdi.kb_config);
310
	} else if (ioctl(fd, MOUSE_GETHWINFO, &mshw) != -1) { /* Is this mouse? */
311
#ifdef notyet /* FreeBSD mouse drivers does not return real vid+pid. */
312
		/* construct USB ID in lowercase hex - "0000:ffff" */
313
		snprintf(pnp_usb_id, sizeof(pnp_usb_id), "%04x:%04x",
314
		    mshw.hwid, mshw.model);
315
		attrs.usb_id = pnp_usb_id;
316
#endif
317
318
		switch (mshw.type) {
319
		case MOUSE_MOUSE:
320
		case MOUSE_TRACKBALL:
321
		case MOUSE_STICK:
322
			attrs.flags = ATTR_POINTER;
323
			break;
324
		case MOUSE_PAD:
325
			attrs.flags = ATTR_TOUCHPAD;		
326
			break;
327
		}
328
		LogMessage(X_INFO, "config/devd: detected mouse: hwid=%04x, model=%04x, type=%04x, iftype=%04x, buttons=%04x\n",
329
		    mshw.hwid, mshw.model, mshw.type, mshw.iftype, mshw.buttons);
330
	} else if (ioctl(fd, JSIOCGNAME((sizeof(product) - 1)), product) != -1) { /* Is this joystick? */
331
		attrs.product = product;
332
		attrs.flags = ATTR_JOYSTICK;
333
		LogMessage(X_INFO, "config/devd: detected joystick: %s\n",
334
		    product);
335
	} else if (ioctl(fd, EVIOCGID, &iid) != -1 &&
336
	    ioctl(fd, EVIOCGNAME((sizeof(product) - 1)), product) != -1) { /* Is this event? */
337
		/* construct USB ID in lowercase hex - "0000:ffff" */
338
		snprintf(pnp_usb_id, sizeof(pnp_usb_id), "%04x:%04x",
339
		    iid.vendor, iid.product);
340
		attrs.usb_id = pnp_usb_id;
341
		attrs.product = product;
342
		attrs.flags = (ATTR_POINTER | ATTR_TABLET | ATTR_TOUCHPAD);
343
		LogMessage(X_INFO, "config/devd: detected event: %s, bustype=%04x, vendor=%04x, product=%04x, version=%04x\n",
344
		    product, iid.bustype, iid.vendor, iid.product, iid.version);
345
	}
346
347
	if (NULL == attrs.usb_id) { /* Is this webcamd device? */
348
		if (ioctl(fd, WEBCAMD_IOCTL_GET_USB_VENDOR_ID, &vid) != -1 &&
349
		    ioctl(fd, WEBCAMD_IOCTL_GET_USB_PRODUCT_ID, &pid) != -1) {
350
			snprintf(pnp_usb_id, sizeof(pnp_usb_id),
351
			    "%04x:%04x", vid, pid);
352
			attrs.usb_id = pnp_usb_id;
353
			LogMessage(X_INFO, "config/devd: WebCamD device: %s\n", pnp_usb_id);
354
		}
355
	}
356
357
	close(fd);
358
359
skip_ioctl:
360
	/* Try to get device info via sysctl(). */
361
	if (NULL == attrs.usb_id && NULL == attrs.pnp_id) {
362
		snprintf(sysctlname, sizeof(sysctlname), "dev.%s.%s.%%pnpinfo",
363
		    hwtype->dev_name, (dev_name + hwtype->dev_name_size));
364
		sdata = sysctl_get_str(sysctlname, &sdata_size);
365
		if (NULL != sdata) {
366
			ptr_vid = devd_get_val(sdata, sdata_size,
367
			    "vendor", 6, &vid_size);
368
			ptr_pid = devd_get_val(sdata, sdata_size,
369
			    "product", 7, &pid_size);
370
			if (NULL != ptr_vid && NULL != ptr_pid) { /* usb_id */
371
				ptr_vid[vid_size] = 0;
372
				ptr_pid[pid_size] = 0;
373
				snprintf(pnp_usb_id, sizeof(pnp_usb_id),
374
				    "%s:%s", ptr_vid, ptr_pid);
375
				attrs.usb_id = pnp_usb_id;
376
				LogMessage(X_INFO, "config/devd: usb_id: %s\n", pnp_usb_id);
377
			} else { /* pnp_id */
378
				strlcpy(pnp_usb_id, sdata, sizeof(pnp_usb_id));
379
				attrs.pnp_id = pnp_usb_id;
380
			}
381
			free(sdata);
382
		}
383
	}
384
	if (NULL == attrs.vendor || NULL == attrs.product) {
385
		snprintf(sysctlname, sizeof(sysctlname), "dev.%s.%s.%%desc",
386
		    hwtype->dev_name, (dev_name + hwtype->dev_name_size));
387
		sdata = sysctl_get_str(sysctlname, &sdata_size);
388
		if (NULL != sdata) {
389
			/* Vendor. */
390
			ptr_pid = memchr(sdata, ' ', sdata_size);
391
			if (NULL != ptr_pid)
392
				ptr_pid[0] = 0;
393
			strlcpy(vendor, sdata, sizeof(vendor));
394
			attrs.vendor = vendor;
395
			/* Product. */
396
			if (NULL == attrs.product && NULL != ptr_pid) {
397
				ptr_pid ++;
398
				ptr_vid = memchr(ptr_pid, ',',
399
				    (sdata_size - (ptr_pid - sdata)));
400
				if (NULL != ptr_vid)
401
					ptr_vid[0] = 0;
402
				strlcpy(product, ptr_pid, sizeof(product));
403
				attrs.product = product;
404
			} else {
405
				product[0] = 0;
406
			}
407
			free(sdata);
408
			LogMessage(X_INFO, "config/devd: vendor: %s, product: %s\n", vendor, product);
409
		}
410
	}
411
412
	/* Init options. */
413
	options = input_option_new(NULL, "_source", "server/devd");
414
	if (NULL == options)
415
		goto err_out;
416
417
	options = input_option_new(options, "config_info", config_info);
418
	if (NULL == options)
419
		goto err_out;
420
421
	options = input_option_new(options, "name",
422
	    ((NULL != attrs.product) ? attrs.product : dev_name));
423
	if (NULL == options)
424
		goto err_out;
425
426
	if (fd >= 0) {
427
		options = input_option_new(options, "device", dev_path);
428
		if (NULL == options)
429
			goto err_out;
430
	}
431
432
	if (NULL != hwtype->xdriver) {
433
		options = input_option_new(options, "driver", hwtype->xdriver);
434
		if (NULL == options)
435
			goto err_out;
436
	}
437
438
	LogMessage(X_INFO, "config/devd: adding input device %s\n", dev_path);
439
	NewInputDeviceRequest(options, &attrs, &dev_iptr);
440
	goto done;
441
442
err_out:
443
	LogMessage(X_INFO, "config/devd: error adding device '%s'\n",
444
	    dev_path);
445
done:
446
	input_option_free_list(&options);
447
}
448
449
static void
450
device_removed(const char *dev_name, size_t dev_name_size)
451
{
452
	char config_info[(PATH_MAX + 32)];
453
454
	if (NULL == dev_name || 0 == dev_name_size || PATH_MAX < dev_name_size)
455
		return;
456
	if (NULL == get_dev_type_by_name(dev_name, dev_name_size))
457
		return; /* Device not in list - unknown. */
458
	memcpy(config_info, DEVD_PATH_DEV, DEVD_PATH_DEV_LEN);
459
	memcpy((config_info + DEVD_PATH_DEV_LEN), dev_name, dev_name_size);
460
	config_info[(DEVD_PATH_DEV_LEN + dev_name_size)] = 0;
461
462
	LogMessage(X_INFO, "config/devd: removing input device '%s'\n",
463
	    (config_info + DEVD_PATH_DEV_LEN));
464
465
	remove_devices("devd", config_info);
466
}
467
468
469
static void
470
disconnect_devd(int sock)
471
{
472
	if (sock >= 0) {
473
		RemoveGeneralSocket(sock);
474
		close(sock);
475
	}
476
}
477
478
static int
479
connect_devd(void)
480
{
481
	int sock;
482
	struct sockaddr_un devd;
483
484
	sock = socket(AF_UNIX, SOCK_STREAM, 0);
485
	if (sock < 0) {
486
		LogMessage(X_ERROR, "config/devd: fail opening stream socket\n");
487
		return (-1);
488
	}
489
490
	devd.sun_family = AF_UNIX;
491
	memcpy(devd.sun_path, DEVD_SOCK_PATH, sizeof(DEVD_SOCK_PATH));
492
	if (connect(sock, (struct sockaddr*)&devd, sizeof(devd)) < 0) {
493
		close(sock);
494
		LogMessage(X_ERROR, "config/devd: fail to connect to devd\n");
495
		return (-1);
496
	}
497
498
	AddGeneralSocket(sock);
499
500
	return (sock);
501
}
502
503
static CARD32
504
reconnect_handler(OsTimerPtr timer, CARD32 time, void *arg)
505
{
506
	devd_buf_used = 0;
507
	devd_skt = connect_devd();
508
	if (-1 == devd_skt) /* Try again after RECONNECT_DELAY */
509
		return (RECONNECT_DELAY);
510
	TimerFree(rtimer);
511
	rtimer = NULL;
512
	LogMessage(X_INFO, "config/devd: reopening devd socket\n");
513
514
	return (0);
515
}
516
517
static void
518
wakeup_handler(void *data, int err, void *read_mask)
519
{
520
	int error;
521
	char *ptr, *line, *val, *cdev;
522
	size_t line_size, val_size, cdev_size;
523
	ssize_t ios;
524
525
	if (err < 0)
526
		return;
527
	if (!FD_ISSET(devd_skt, (fd_set*)read_mask))
528
		return;
529
	/* Read new data. */
530
	for (;;) {
531
		ios = recv(devd_skt, (devd_buf + devd_buf_used), 
532
		    (sizeof(devd_buf) - devd_buf_used), MSG_DONTWAIT);
533
		if (ios > 0) { /* Read OK. */
534
			devd_buf_used += ios;
535
			continue; /* Try to read more. */
536
		}
537
		/* Something wrong. */
538
		error = errno;
539
		if (error == EAGAIN)
540
			break; /* All avaible data readed. */
541
		if (error == EINTR)
542
			continue;
543
		if (sizeof(devd_buf) == devd_buf_used) { /* Message to long, reset buf. */
544
			devd_buf_used = 0;
545
			continue;
546
		}
547
		/* devd socket is lost */
548
		disconnect_devd(devd_skt);
549
		rtimer = TimerSet(NULL, 0, 1, reconnect_handler, NULL);
550
		LogMessage(X_WARNING, "config/devd: devd socket read error: %i - %s\n", error, strerror(error));
551
		return;
552
	}
553
	ptr = memchr(devd_buf, '\n', devd_buf_used);
554
	if (NULL == ptr)
555
		return;
556
557
	/* Process data. */
558
	line = (devd_buf + 1);
559
	for (;;) {
560
		line_size = (ptr - line);
561
		if (DEVD_EVENT_NOTIFY != (*(line - 1)))
562
			goto move_next_event; /* Handle only notify. */
563
		/* Check: is system=DEVFS. */
564
		val = devd_get_val(line, line_size, "system", 6, &val_size);
565
		if (!is_meuqual(val, val_size, "DEVFS", 5))
566
			goto move_next_event;
567
		/* Check: is subsystem=CDEV. */
568
		val = devd_get_val(line, line_size, "subsystem", 9, &val_size);
569
		if (!is_meuqual(val, val_size, "CDEV", 4))
570
			goto move_next_event;
571
		/* Get device name. */
572
		cdev = devd_get_val(line, line_size, "cdev", 4, &cdev_size);
573
		if (NULL == cdev)
574
			goto move_next_event;
575
		/* Get event type. */
576
		val = devd_get_val(line, line_size, "type", 4, &val_size);
577
		if (is_meuqual(val, val_size, "CREATE", 6)) {
578
			device_added(cdev, cdev_size, 0);
579
		} else if (is_meuqual(val, val_size, "DESTROY", 7)) {
580
			device_removed(cdev, cdev_size);
581
		}
582
583
move_next_event:
584
		line += (line_size + 2); /* Skip '\n' and event type byte. */
585
		line_size = (line - devd_buf);
586
		if (devd_buf_used <= line_size) {
587
			devd_buf_used = 0;
588
			return;
589
		}
590
		ptr = memchr(line, '\n', (devd_buf_used - line_size));
591
		if (NULL == ptr)
592
			break;
593
	}
594
	/* Save line without end marker. */
595
	devd_buf_used -= (line_size - 1);
596
	memmove(devd_buf, (line - 1), devd_buf_used);
597
}
598
599
static void
600
block_handler(void *data, struct timeval **tv, void *read_mask)
601
{
602
}
603
604
int
605
as_cfg_load_dir(char *dir_name)
606
{
607
	return (0);
608
}
609
610
int
611
config_devd_init(void)
612
{
613
	size_t i, j, dir_cnt, sdir_cnt, tm;
614
	char devicename[PATH_MAX];
615
	struct dirent *de, **namelist, *sde, **snamelist;
616
617
	LogMessage(X_INFO, "config/devd: probing input devices...\n");
618
619
	/*
620
	 * Add fake keyboard and give up on keyboards management
621
	 * if kbdmux is enabled
622
	 */
623
	is_kbdmux = is_kbdmux_enabled();
624
	if (is_kbdmux)
625
		device_added("kbdmux0", 7, 1);
626
627
	/* Scan /dev/ for devices. */
628
	dir_cnt = scandir(_PATH_DEV, &namelist, 0, alphasort);
629
	for (i = 0; i < dir_cnt; i ++) {
630
		de = namelist[i];
631
		if (is_de_euqual(de, ".", 1) ||
632
		    is_de_euqual(de, "..", 2)) {
633
			free(de);
634
			continue;
635
		}
636
		if (DT_DIR != de->d_type) {
637
			device_added(de->d_name, de->d_namlen, 0);
638
		} else { /* Sub folder. */
639
			snprintf(devicename, sizeof(devicename),
640
			    _PATH_DEV "%s", de->d_name);
641
			sdir_cnt = scandir(devicename, &snamelist, 0, alphasort);
642
			for (j = 0; j < sdir_cnt; j ++) {
643
				sde = snamelist[j];
644
				if (!is_de_euqual(sde, ".", 1) &&
645
				    !is_de_euqual(sde, "..", 2) &&
646
				    DT_DIR != sde->d_type) {
647
					tm = snprintf(devicename, sizeof(devicename),
648
					    "%s/%s", de->d_name, sde->d_name);
649
					device_added(devicename, tm, 0);
650
				}
651
				free(sde);
652
			}
653
			free(snamelist);
654
		}
655
		free(de);
656
	}
657
	free(namelist);
658
659
	devd_buf_used = 0;
660
	devd_skt = connect_devd();
661
	if (-1 == devd_skt)
662
		return (0);
663
664
	/* Register wakeup handler */
665
	RegisterBlockAndWakeupHandlers(block_handler, wakeup_handler, NULL);
666
667
	return (1);
668
}
669
670
void
671
config_devd_fini(void)
672
{
673
	LogMessage(X_INFO, "config/devd: terminating backend...\n");
674
675
	if (rtimer) {
676
		TimerFree(rtimer);
677
		rtimer = NULL;
678
	}
679
680
	disconnect_devd(devd_skt);
681
682
	RemoveBlockAndWakeupHandlers(block_handler, wakeup_handler, NULL);
683
}

Return to bug 196678