From owner-freebsd-ports-bugs@FreeBSD.ORG Wed Oct 30 12:10:00 2013 Return-Path: Delivered-To: freebsd-ports-bugs@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTP id 81DAEC28 for ; Wed, 30 Oct 2013 12:10:00 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 59BBB2BA6 for ; Wed, 30 Oct 2013 12:10:00 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.7/8.14.7) with ESMTP id r9UCA0nf081797 for ; Wed, 30 Oct 2013 12:10:00 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.7/8.14.7/Submit) id r9UCA0g0081796; Wed, 30 Oct 2013 12:10:00 GMT (envelope-from gnats) Resent-Date: Wed, 30 Oct 2013 12:10:00 GMT Resent-Message-Id: <201310301210.r9UCA0g0081796@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-ports-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Vitaly Magerya Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTP id 405E6B9C for ; Wed, 30 Oct 2013 12:04:03 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from oldred.freebsd.org (oldred.freebsd.org [8.8.178.121]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 2CD6D2B6D for ; Wed, 30 Oct 2013 12:04:03 +0000 (UTC) Received: from oldred.freebsd.org ([127.0.1.6]) by oldred.freebsd.org (8.14.5/8.14.7) with ESMTP id r9UC42ZI047916 for ; Wed, 30 Oct 2013 12:04:02 GMT (envelope-from nobody@oldred.freebsd.org) Received: (from nobody@localhost) by oldred.freebsd.org (8.14.5/8.14.5/Submit) id r9UC42Kd047911; Wed, 30 Oct 2013 12:04:02 GMT (envelope-from nobody) Message-Id: <201310301204.r9UC42Kd047911@oldred.freebsd.org> Date: Wed, 30 Oct 2013 12:04:02 GMT From: Vitaly Magerya To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.1 Subject: ports/183478: x11-servers/xorg-server: DEVD backend is broken, here's a fix X-BeenThere: freebsd-ports-bugs@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Ports bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 30 Oct 2013 12:10:00 -0000 >Number: 183478 >Category: ports >Synopsis: x11-servers/xorg-server: DEVD backend is broken, here's a fix >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-ports-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Wed Oct 30 12:10:00 UTC 2013 >Closed-Date: >Last-Modified: >Originator: Vitaly Magerya >Release: FreeBSD 9.2-RELEASE amd64 >Organization: >Environment: >Description: A month ago an update to MESA and related X11 ports [1] introduced an experimental devd-based hotplug backend to xorg-server. Unfortunately that code contains a number of major problems: 1) the code added by xorg-server/files/extra-config_devd.c is literally never called; the call to config_devd_init() was never added to config_init() (in config/config.c of the server); see this mail [2] and PR 182609 [3] 2) files/extra-config_devd.c has a typo: it'll try to load driver "kdb" instead of "kbd", see PR 181660 3) if the above problems are fixed, the backend will crash when used with xorg-server 1.7.7 inside one of the option-parsing routines (I did not pursue a fix for this, so I can't comment on how it'll work if the crash is fixed) 4) the backend always sets 'usb_id' attribute to NULL, thus preventing 'MatchUSBID' directive in xorg.conf from working 5) the backend incorrectly parses vendor and product name, thus making 'MatchVendor' and 'MatchProduct' directives hard to use 6) if devd is restarted when Xorg is running, the backend will lose connection to devd, and will not report any new hardware attaching or old hardware detaching (see mail at [5] for the last three items) To put it shortly, the current devd backend doesn't work. To fix all of the above points I've developed a new devd-based backend, which I propose we use instead. Read a (somewhat) detailed description of it in the mail at [6]. I'm attaching a patch agains current x11-servers/xorg-server port (it's the same patch as at [6], only updated to catch up with the port changes). [1] http://svnweb.freebsd.org/ports?limit_changes=0&view=revision&revision=328711 [2] http://lists.freebsd.org/pipermail/freebsd-x11/2013-September/013645.html [3] http://www.freebsd.org/cgi/query-pr.cgi?pr=ports/182609 [4] http://www.freebsd.org/cgi/query-pr.cgi?pr=ports/181660 [5] http://lists.freebsd.org/pipermail/freebsd-x11/2013-September/013626.html [6] http://lists.freebsd.org/pipermail/freebsd-x11/2013-September/013656.html >How-To-Repeat: >Fix: Patch attached with submission follows: diff -ruN xorg-server.orig/Makefile xorg-server/Makefile --- xorg-server.orig/Makefile 2013-10-24 22:50:23.000000000 +0300 +++ xorg-server/Makefile 2013-10-30 13:00:51.000000000 +0200 @@ -22,13 +22,17 @@ OPTIONS_DEFINE= AIGLX SUID OPTIONS_RADIO= CONF -OPTIONS_RADIO_CONF= HAL DEVD +OPTIONS_RADIO_CONF= HAL AIGLX_DESC= Compile with Accelerated Indirect GLX support SUID_DESC= Install the Xorg server with setuid bit set HAL_DESC= Compile with HAL config support -DEVD_DESC= Use devd for autoconfiguration of input devices (experimental) OPTIONS_DEFAULT=AIGLX SUID HAL +.if defined(WITH_NEW_XORG) +OPTIONS_RADIO_CONF+= DEVD +DEVD_DESC= Use devd for autoconfiguration of input devices (experimental) +.endif + OPTIONS_EXCLUDE_sparc64= HAL .include @@ -109,7 +113,10 @@ .endif .if ${PORT_OPTIONS:MDEVD} -EXTRA_PATCHES+= ${FILESDIR}/extra-config_devd.c +EXTRA_PATCHES+= ${FILESDIR}/extra-devd +PLIST_SUB+= DEVD="" +.else +PLIST_SUB+= DEVD="@comment " .endif .if ${PORT_OPTIONS:MAIGLX} @@ -187,6 +194,7 @@ -e 's|^LTLIBRARIES = |LTLIBRARIES = libglx.la |g' \ ${WRKSRC}/hw/xfree86/dixmods/Makefile.in .if ${PORT_OPTIONS:MDEVD} + @${CP} ${FILESDIR}/devd.c.in ${WRKSRC}/config/devd.c @${ECHO_CMD} -e "\nint config_devd_init(void);\nvoid config_devd_fini(void);" \ >> ${WRKSRC}/config/config-backends.h .endif @@ -210,6 +218,10 @@ .if defined(WITH_NEW_XORG) @${MKDIR} ${PREFIX}/share/X11/xorg.conf.d .endif +.if ${PORT_OPTIONS:MDEVD} + @${INSTALL_DATA} ${FILESDIR}/xhotplug.conf.in ${PREFIX}/etc/devd/xhotplug.conf + @${INSTALL_SCRIPT} ${FILESDIR}/xhotplug.in ${PREFIX}/etc/rc.d/xhotplug +.endif @PKG_PREFIX=${PREFIX} ${SH} ${PKGINSTALL} ${PKGNAME} POST-INSTALL .endif diff -ruN xorg-server.orig/files/devd.c.in xorg-server/files/devd.c.in --- xorg-server.orig/files/devd.c.in 1970-01-01 03:00:00.000000000 +0300 +++ xorg-server/files/devd.c.in 2013-10-30 12:57:31.000000000 +0200 @@ -0,0 +1,376 @@ +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "input.h" +#include "inputstr.h" +#include "hotplug.h" +#include "config-backends.h" +#include "os.h" +#include "opaque.h" /* for 'display' */ + +#define DEVPIPE_PATH "/var/run/xorg-devpipe.pipe.%s" +#define DEVLIST_PATH "/var/run/xorg-devpipe.list" + +static int pipe_fd = -1; +static char pipe_name[256]; + +static int +hex2int(char hex) +{ + return ('0' <= hex && hex <= '9') ? hex - '0' : + ('a' <= hex && hex <= 'f') ? hex - 'a' + 10 : + ('A' <= hex && hex <= 'F') ? hex - 'A' + 10 : 0; +} + +static void +percent_decode(char *string) +{ + char *p, ch; + for (p = string; (ch = *string);) { + if (ch == '%') { + if (!string[1] || !string[2]) break; + *p++ = hex2int(string[1]) * 16 + hex2int(string[2]); + string += 3; + } else { + *p++ = *string++; + } + } + *p = 0; +} + +#if XORG_VERSION_CURRENT > 10800000 +static void +plus_device(const char *descr) +{ + InputAttributes attrs = { }; + DeviceIntPtr dev = NULL; + InputOption *input_options = NULL; + char key[256], *val; + char *devname, *devpath, *config_info, **tag; + int n; + + if (sscanf(descr, "%256s%n", key, &n) < 0) + return; + descr += n; + + devname = strdup(key); + asprintf(&devpath, "/dev/%s", devname); + asprintf(&config_info, "devd:%s", devname); + + if (device_is_duplicate(config_info)) { + LogMessage(X_WARNING, "config/devd: device %s already added\n", devname); + goto free2; + } + + input_options = input_option_new(input_options, "device", devpath); + input_options = input_option_new(input_options, "config_info", config_info); + + attrs.device = strdup(devpath); + + while (sscanf(descr, " %64[^=]%192[^ ]%n", key, &key[65], &n) >= 2) { + descr += n; + percent_decode(val = &key[66]); + LogMessage(X_INFO, "config/devd: %s: %s=<%s>\n", devname, key, val); + input_options = input_option_new(input_options, key, val); + if (!strcmp(key, "product")) attrs.product = strdup(val); + else if (!strcmp(key, "vendor")) attrs.vendor = strdup(val); + else if (!strcmp(key, "pnp_id")) attrs.pnp_id = strdup(val); + else if (!strcmp(key, "usb_id")) attrs.usb_id = strdup(val); + else if (!strcmp(key, "tags")) attrs.tags = xstrtokenize(val, ","); + else if (!strcmp(key, "flags")) { + if (strstr(val, "keyboard")) attrs.flags |= ATTR_KEYBOARD; + if (strstr(val, "pointer")) attrs.flags |= ATTR_POINTER; + if (strstr(val, "joystick")) attrs.flags |= ATTR_JOYSTICK; + if (strstr(val, "tablet")) attrs.flags |= ATTR_TABLET; + if (strstr(val, "touchpad")) attrs.flags |= ATTR_TOUCHPAD; + if (strstr(val, "touchscreen")) attrs.flags |= ATTR_TOUCHSCREEN; + }; + } + + if (input_option_find(input_options, "name") == NULL) + input_options = input_option_new(input_options, "name", devname); + + if (input_options == NULL) { + LogMessage(X_ERROR, "config/devd: can't allocate space for input options\n"); + goto free; + } + + LogMessage(X_INFO, "config/devd: adding device %s\n", devname); + NewInputDeviceRequest(input_options, &attrs, &dev); + +free: + input_option_free_list(&input_options); + + if (attrs.product) free(attrs.product); + if (attrs.vendor) free(attrs.vendor); + if (attrs.device) free(attrs.device); + if (attrs.pnp_id) free(attrs.pnp_id); + if (attrs.usb_id) free(attrs.usb_id); + if (attrs.tags) { + for (tag = attrs.tags; *tag; tag++) free(*tag); + free(attrs.tags); + } +free2: + free(config_info); + free(devpath); + free(devname); +} + +#else + +/* This branch is a Frankensteinian monster. + * For some reason if you add devices from _init, xserver will + * fail to load the drivers. Also, wakeup handler never gets + * called. In short, this is a disaster, kill it with fire. + * (Only left here for reference). + */ + +#error "DEVD backend does not work with xorg-server 1.7.7" + +/* from new config/config.c */ +static int +device_is_duplicate(char *config_info) +{ + DeviceIntPtr dev; + + for (dev = inputInfo.devices; dev; dev = dev->next) + if (dev->config_info && (strcmp(dev->config_info, config_info) == 0)) + return 1; + + for (dev = inputInfo.off_devices; dev; dev = dev->next) + if (dev->config_info && (strcmp(dev->config_info, config_info) == 0)) + return 1; + + return 0; +} + +/* from new config/config.c */ +static void +remove_device(const char *backend, DeviceIntPtr dev) +{ + /* this only gets called for devices that have already been added */ + LogMessage(X_INFO, "config/devd: removing device %s\n", dev->name); + + /* Call PIE here so we don't try to dereference a device that's + * already been removed. */ + OsBlockSignals(); + ProcessInputEvents(); + DeleteInputDeviceRequest(dev); + OsReleaseSignals(); +} + +/* from new config/config.c */ +static void +remove_devices(const char *backend, const char *config_info) +{ + DeviceIntPtr dev, next; + + for (dev = inputInfo.devices; dev; dev = next) { + next = dev->next; + if (dev->config_info && strcmp(dev->config_info, config_info) == 0) + remove_device(backend, dev); + } + for (dev = inputInfo.off_devices; dev; dev = next) { + next = dev->next; + if (dev->config_info && strcmp(dev->config_info, config_info) == 0) + remove_device(backend, dev); + } +} + +/* from old config/hal.c */ +static void +add_option(InputOption **options, const char *key, const char *value) +{ + if (!value || *value == '\0') + return; + + for (; *options; options = &(*options)->next) + ; + *options = xcalloc(sizeof(**options), 1); + if (!*options) /* Yeesh. */ + return; + (*options)->key = xstrdup(key); + (*options)->value = xstrdup(value); + (*options)->next = NULL; +} + + +static void +plus_device(const char *descr) +{ + DeviceIntPtr dev = NULL; + InputOption *input_options = NULL, *opt; + char key[256], *val; + char *devname, *devpath, *config_info, **tag; + int n, gotname = 0; + + if (sscanf(descr, "%256s%n", key, &n) < 0) + return; + descr += n; + + devname = strdup(key); + asprintf(&devpath, "/dev/%s", devname); + asprintf(&config_info, "devd:%s", devname); + + if (device_is_duplicate(config_info)) { + LogMessage(X_WARNING, "config/devd: device %s already added\n", devname); + goto free2; + } + + /*input_options = calloc(sizeof(*input_options), 1); + if (input_options == NULL) { + LogMessage(X_ERROR, "config/devd: calloc() failed\n"); + goto free2; + }*/ + + add_option(&input_options, "device", devpath); + add_option(&input_options, "config_info", config_info); + + while (sscanf(descr, " %64[^=]%192[^ ]%n", key, &key[65], &n) >= 2) { + descr += n; + percent_decode(val = &key[66]); + LogMessage(X_INFO, "config/devd: %s: %s=<%s>\n", devname, key, val); + add_option(&input_options, key, val); + if (strcmp(key, "name") == 0) gotname = 1; + } + + if (!gotname) + add_option(&input_options, "name", devname); + + LogMessage(X_INFO, "config/devd: adding device %s\n", devname); + NewInputDeviceRequest(input_options, &dev); + +free: + while ((opt = input_options)) { + input_options = opt->next; + if (opt->key) free(opt->key); + if (opt->value) free(opt->value); + free(opt); + } +free2: + free(config_info); + free(devpath); + free(devname); +} +#endif + +static void +minus_device(const char *descr) +{ + char devname[192], config_info[192 + 8]; + + if (sscanf(descr, "%192s", devname) < 0) + return; + sprintf(config_info, "devd:%s", devname); + remove_devices("devd", config_info); +} + +static void +block_handler(pointer data, struct timeval **tv, pointer read_mask) +{ +} + +static void +wakeup_handler(pointer data, int err, pointer read_mask) +{ + char buffer[1024]; + int fd, n; + + if (err < 0) { + //LogMessage(X_WARNING, "config/devd: ignoring error %d\n", err); + return; + } + + if (FD_ISSET(pipe_fd, (fd_set *) read_mask)) { + fd = accept(pipe_fd, NULL, NULL); + if (fd < 0) { + LogMessage(X_WARNING, "config/devd: can't accept(): %s\n", strerror(errno)); + return; + } + // Please, don't block :) + n = recv(fd, buffer, sizeof(buffer) - 1, 0); + if (n < 0) { + LogMessage(X_WARNING, "config/devd: recv() error: %s\n", strerror(errno)); + close(fd); + return; + } + close(fd); + buffer[n] = 0; + LogMessage(X_INFO, "config/devd: received: %s\n", buffer); + if (buffer[0] == '+') plus_device(&buffer[1]); + if (buffer[0] == '-') minus_device(&buffer[1]); + } +} + +static void +plus_devlist_devices(void) +{ + FILE *db; + char *line = NULL; + size_t linecap = 0; + ssize_t linelen; + + db = fopen(DEVLIST_PATH, "rb"); + if (db == NULL) return; + + while ((linelen = getline(&line, &linecap, db)) > 0) { + if (line[linelen - 1] == '\n') { + line[linelen - 1] = 0; + plus_device(line); + } else { + LogMessage(X_ERROR, "config/devd: %s doesn not end with a newline\n", DEVLIST_PATH); + } + } + if (line) free(line); +} + +int +config_devd_init(void) +{ + struct sockaddr_un addr; + + snprintf(pipe_name, sizeof(pipe_name), DEVPIPE_PATH, display); + pipe_fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (pipe_fd < 0) { + LogMessage(X_ERROR, "config/devd: socket() failed: %s\n", strerror(errno)); + return 0; + } + addr.sun_family = AF_UNIX; + strlcpy(addr.sun_path, pipe_name, sizeof(addr.sun_path)); + unlink(addr.sun_path); + if (bind(pipe_fd, (struct sockaddr*)&addr, sizeof(addr)) != 0) { + LogMessage(X_ERROR, "config/devd: bind() failed: %s\n", strerror(errno)); + return 0; + } + chmod(addr.sun_path, 0666); + if (listen(pipe_fd, 1) != 0) { + LogMessage(X_ERROR, "config/devd: listen() failed: %s\n", strerror(errno)); + return 0; + } + LogMessage(X_INFO, "config/devd: listening on %s\n", pipe_name); + RegisterBlockAndWakeupHandlers(block_handler, wakeup_handler, NULL); + AddGeneralSocket(pipe_fd); + plus_devlist_devices(); + return 1; +} + +void +config_devd_fini(void) +{ + if (pipe_fd >= 0) { + RemoveGeneralSocket(pipe_fd); + RemoveBlockAndWakeupHandlers(block_handler, wakeup_handler, NULL); + close(pipe_fd); + unlink(pipe_name); + pipe_fd = -1; + } + LogMessage(X_INFO, "config/devd: finished\n"); +} diff -ruN xorg-server.orig/files/extra-config_devd.c xorg-server/files/extra-config_devd.c --- xorg-server.orig/files/extra-config_devd.c 2013-09-29 20:01:41.000000000 +0300 +++ xorg-server/files/extra-config_devd.c 1970-01-01 03:00:00.000000000 +0300 @@ -1,481 +0,0 @@ ---- /dev/null 2013-08-03 00:44:23.000000000 +0200 -+++ config/devd.c 2013-08-03 00:45:15.162836806 +0200 -@@ -0,0 +1,478 @@ -+/* -+ * Copyright © 2012 Baptiste Daroussin -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ * -+ * Author: Baptiste Daroussin -+ */ -+ -+#ifdef HAVE_DIX_CONFIG_H -+#include -+#endif -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "input.h" -+#include "inputstr.h" -+#include "hotplug.h" -+#include "config-backends.h" -+#include "os.h" -+ -+#define DEVD_SOCK_PATH "/var/run/devd.pipe" -+ -+#define DEVD_EVENT_ADD '+' -+#define DEVD_EVENT_REMOVE '-' -+ -+static int sock_devd = -1; -+ -+#if XORG_VERSION_CURRENT < 10800000 -+enum { -+ ATTR_KEYBOARD, -+ ATTR_POINTER, -+ ATTR_JOYSTICK, -+ ATTR_TOUCHPAD, -+ ATTR_TOUCHSCREEN, -+}; -+#endif -+ -+struct hw_type { -+ const char *driver; -+ int flag; -+ const char *xdriver; -+}; -+ -+static struct hw_type hw_types[] = { -+ { "ukbd", ATTR_KEYBOARD, "kdb" }, -+ { "atkbd", ATTR_KEYBOARD, "kdb" }, -+ { "ums", ATTR_POINTER, "mouse" }, -+ { "psm", ATTR_POINTER, "mouse" }, -+ { "uhid", ATTR_POINTER, "mouse" }, -+ { "joy", ATTR_JOYSTICK, NULL }, -+ { "atp", ATTR_TOUCHPAD, NULL }, -+ { "uep", ATTR_TOUCHSCREEN, NULL }, -+ { NULL, -1, NULL }, -+}; -+ -+#if XORG_VERSION_CURRENT < 10800000 -+static void -+add_option(InputOption **options, const char *key, const char *value) -+{ -+ if (!value || *value == '\0') -+ return; -+ -+ for (; *options; options = &(*options)->next) -+ ; -+ *options = calloc(sizeof(**options), 1); -+ if (!*options) /* Yeesh. */ -+ return; -+ (*options)->key = xstrdup(key); -+ (*options)->value = xstrdup(value); -+ (*options)->next = NULL; -+} -+ -+static void -+remove_device(DeviceIntPtr dev) -+{ -+ /* this only gets called for devices that have already been added */ -+ LogMessage(X_INFO, "config/devd: removing device %s\n", dev->name); -+ -+ /* Call PIE here so we don't try to dereference a device that's -+ * already been removed. */ -+ OsBlockSignals(); -+ ProcessInputEvents(); -+ DeleteInputDeviceRequest(dev); -+ OsReleaseSignals(); -+} -+ -+static bool -+device_is_duplicate(char *config_info) -+{ -+ DeviceIntPtr dev; -+ -+ for (dev = inputInfo.devices; dev; dev = dev->next) -+ if (dev->config_info && (strcmp(dev->config_info, config_info) == 0)) -+ return true; -+ -+ for (dev = inputInfo.off_devices; dev; dev = dev->next) -+ if (dev->config_info && (strcmp(dev->config_info, config_info) == 0)) -+ return true; -+ -+ return false; -+} -+ -+#endif -+ -+static bool -+sysctl_exists(const char *format, ...) -+{ -+ va_list args; -+ char *name = NULL; -+ size_t len; -+ int ret; -+ -+ if (format == NULL) -+ return false; -+ -+ va_start(args, format); -+ vasprintf(&name, format, args); -+ va_end(args); -+ -+ ret = sysctlbyname(name, NULL, &len, NULL, 0); -+ -+ if (ret == -1) -+ len = 0; -+ -+ free(name); -+ return (len > 0); -+} -+ -+static char * -+sysctl_get_str(const char *format, ...) -+{ -+ va_list args; -+ char *name = NULL; -+ char *dest = NULL; -+ size_t len; -+ -+ if (format == NULL) -+ return NULL; -+ -+ va_start(args, format); -+ vasprintf(&name, format, args); -+ va_end(args); -+ -+ if (sysctlbyname(name, NULL, &len, NULL, 0) == 0) { -+ dest = malloc(len + 1); -+ if (sysctlbyname(name, dest, &len, NULL, 0) == 0) -+ dest[len] = '\0'; -+ else { -+ free(dest); -+ dest = NULL; -+ } -+ } -+ -+ free(name); -+ return dest; -+} -+ -+static void -+device_added(char *line) -+{ -+ char *walk; -+ char *path; -+ char *vendor; -+ char *product = NULL; -+ char *config_info = NULL; -+ InputOption *options = NULL; -+#if XORG_VERSION_CURRENT > 10800000 -+ InputAttributes attrs = {}; -+#else -+ InputOption *tmpo; -+#endif -+ DeviceIntPtr dev = NULL; -+ int i, rc; -+ -+ walk = strchr(line, ' '); -+ if (walk != NULL) -+ walk[0] = '\0'; -+ -+ for (i = 0; hw_types[i].driver != NULL; i++) { -+ if (strncmp(line, hw_types[i].driver, -+ strlen(hw_types[i].driver)) == 0 && -+ isnumber(*(line + strlen(hw_types[i].driver)))) { -+#if XORG_VERSION_CURRENT > 10800000 -+ attrs.flags |= hw_types[i].flag; -+#endif -+ break; -+ } -+ } -+ if (hw_types[i].driver == NULL) { -+ LogMessageVerb(X_INFO, 10, "config/devd: ignoring device %s\n", line); -+ return; -+ } -+ -+#if XORG_VERSION_CURRENT < 10800000 -+ if (hw_types[i].xdriver == NULL) { -+ LogMessageVerb(X_INFO, 10, "config/devd: ignoring device %s\n", line); -+ return; -+ } -+#endif -+ if (asprintf(&path, "/dev/%s", line) == -1) -+ return; -+ -+#if XORG_VERSION_CURRENT < 10800000 -+ options = calloc(sizeof(*options), 1); -+ if (!options) -+ return; -+ -+ add_option(&options, "_source", "server/devd"); -+#else -+ options = input_option_new(NULL, "_source", "server/devd"); -+ if (!options) -+ return; -+#endif -+ -+ vendor = sysctl_get_str("dev.%s.%s.%%desc", hw_types[i].driver, line + strlen(hw_types[i].driver)); -+ if (vendor == NULL) { -+#if XORG_VERSION_CURRENT > 10800000 -+ attrs.vendor = strdup("(unnamed)"); -+#endif -+ } else { -+ if ((product = strchr(vendor, ' ')) != NULL) { -+ product[0] = '\0'; -+ product++; -+ } -+#if XORG_VERSION_CURRENT > 10800000 -+ attrs.vendor = strdup(vendor); -+#endif -+ if (product != NULL && (walk = strchr(product, ',')) != NULL) -+ walk[0] = '\0'; -+#if XORG_VERSION_CURRENT > 10800000 -+ attrs.product = strdup(product != NULL ? product : "(unnamed)"); -+ options = input_option_new(options, "name", product != NULL ? product : "(unnamed)"); -+#else -+ add_option(&options, "name", product != NULL ? product : "(unnamed)"); -+#endif -+ } -+#if XORG_VERSION_CURRENT > 10800000 -+ attrs.usb_id = NULL; -+ options = input_option_new(options, "path", path); -+ options = input_option_new(options, "device", path); -+#else -+ add_option(&options, "path", path); -+ add_option(&options, "device", path); -+#endif -+ -+#if XORG_VERSION_CURRENT < 10800000 -+ add_option(&options, "driver", hw_types[i].xdriver); -+#endif -+ -+ if (asprintf(&config_info, "devd:%s", line) == -1) { -+ config_info = NULL; -+ goto unwind; -+ } -+ -+ if (device_is_duplicate(config_info)) { -+ LogMessage(X_WARNING, "config/devd: device %s already added. " -+ "Ignoring.\n", product != NULL ? product : "(unnamed)"); -+ goto unwind; -+ } -+ -+#if XORG_VERSION_CURRENT < 10800000 -+ add_option(&options, "config_info", config_info); -+#else -+ options = input_option_new(options, "config_info", config_info); -+#endif -+ LogMessage(X_INFO, "config/devd: Adding input device %s (%s)\n", -+ product != NULL ? product : "(unnamed)", path); -+ -+#if XORG_VERSION_CURRENT > 10800000 -+ rc = NewInputDeviceRequest(options, &attrs, &dev); -+#else -+ rc = NewInputDeviceRequest(options, &dev); -+#endif -+ -+ if (rc != Success) -+ goto unwind; -+ -+ unwind: -+ free(config_info); -+#if XORG_VERSION_CURRENT < 10800000 -+ while ((tmpo = options)) { -+ options = tmpo->next; -+ free(tmpo->key); /* NULL if dev != NULL */ -+ free(tmpo->value); /* NULL if dev != NULL */ -+ free(tmpo); -+ } -+#else -+ input_option_free_list(&options); -+#endif -+ -+#if XORG_VERSION_CURRENT > 10800000 -+ free(attrs.usb_id); -+ free(attrs.product); -+ free(attrs.device); -+ free(attrs.vendor); -+#endif -+ -+ return; -+} -+ -+static void -+device_removed(char *line) -+{ -+ char *walk; -+ char *value; -+#if XORG_VERSION_CURRENT < 10800000 -+ DeviceIntPtr dev, next; -+#endif -+ -+ walk = strchr(line, ' '); -+ if (walk != NULL) -+ walk[0] = '\0'; -+ -+ if (asprintf(&value, "devd:%s", line) == -1) -+ return; -+ -+#if XORG_VERSION_CURRENT > 10800000 -+ remove_devices("dev", value); -+#else -+ for (dev = inputInfo.devices; dev; dev = next) { -+ next = dev->next; -+ if (dev->config_info && strcmp(dev->config_info, value) == 0) -+ remove_device(dev); -+ } -+ for (dev = inputInfo.off_devices; dev; dev = next) { -+ next = dev->next; -+ if (dev->config_info && strcmp(dev->config_info, value) == 0) -+ remove_device(dev); -+ } -+#endif -+ -+ free(value); -+} -+ -+static ssize_t -+socket_getline(int fd, char **out) -+{ -+ char *buf; -+ ssize_t ret, cap, sz = 0; -+ char c; -+ -+ cap = 1024; -+ buf = malloc(cap * sizeof(char)); -+ if (!buf) -+ return -1; -+ -+ for (;;) { -+ ret = read(sock_devd, &c, 1); -+ if (ret < 1) { -+ free(buf); -+ return -1; -+ } -+ -+ if (c == '\n') -+ break; -+ -+ if (sz + 1 >= cap) { -+ cap *= 2; -+ buf = realloc(buf, cap *sizeof(char)); -+ } -+ buf[sz] = c; -+ sz++; -+ } -+ -+ buf[sz] = '\0'; -+ if (sz > 0) -+ *out = buf; -+ else -+ free(buf); -+ -+ return sz; /* number of bytes in the line, not counting the line break*/ -+} -+ -+static void -+wakeup_handler(pointer data, int err, pointer read_mask) -+{ -+ char *line = NULL; -+ -+ if (err < 0) -+ return; -+ -+ if (FD_ISSET(sock_devd, (fd_set *)read_mask)) { -+ if (socket_getline(sock_devd, &line) < 0) -+ return; -+ -+ switch(*line) { -+ case DEVD_EVENT_ADD: -+ device_added(line++); -+ break; -+ case DEVD_EVENT_REMOVE: -+ device_removed(line++); -+ break; -+ default: -+ break; -+ } -+ free(line); -+ } -+} -+ -+static void -+block_handler(pointer data, struct timeval **tv, pointer read_mask) -+{ -+} -+ -+int -+config_devd_init(void) -+{ -+ struct sockaddr_un devd; -+ char devicename[1024]; -+ int i, j; -+ -+ /* first scan the sysctl to determine the hardware if needed */ -+ -+ for (i = 0; hw_types[i].driver != NULL; i++) { -+ for (j = 0; sysctl_exists("dev.%s.%i.%%desc", hw_types[i].driver, j); j++) { -+ snprintf(devicename, 1024, "%s%i", hw_types[i].driver, j); -+ device_added(devicename); -+ } -+ -+ } -+ sock_devd = socket(AF_UNIX, SOCK_STREAM, 0); -+ if (sock_devd < 0) { -+ ErrorF("config/devd: Fail opening stream socket"); -+ return 0; -+ } -+ -+ devd.sun_family = AF_UNIX; -+ strlcpy(devd.sun_path, DEVD_SOCK_PATH, sizeof(devd.sun_path)); -+ -+ if (connect(sock_devd, (struct sockaddr *) &devd, sizeof(struct sockaddr_un)) < 0) { -+ close(sock_devd); -+ ErrorF("config/devd: Fail to connect to devd"); -+ return 0; -+ } -+ -+ RegisterBlockAndWakeupHandlers(block_handler, wakeup_handler, NULL); -+ AddGeneralSocket(sock_devd); -+ -+ return 1; -+} -+ -+void -+config_devd_fini(void) -+{ -+ if (sock_devd < 0) -+ return; -+ -+ RemoveGeneralSocket(sock_devd); -+ RemoveBlockAndWakeupHandlers(block_handler, wakeup_handler, NULL); -+ close(sock_devd); -+} diff -ruN xorg-server.orig/files/extra-devd xorg-server/files/extra-devd --- xorg-server.orig/files/extra-devd 1970-01-01 03:00:00.000000000 +0300 +++ xorg-server/files/extra-devd 2013-10-30 12:59:15.000000000 +0200 @@ -0,0 +1,52 @@ +--- config/config.c.orig 2013-09-19 20:20:55.000000000 +0300 ++++ config/config.c 2013-09-19 20:23:16.000000000 +0300 +@@ -56,6 +56,8 @@ + if (!config_wscons_init()) + ErrorF("[config] failed to initialise wscons\n"); + #endif ++ if (!config_devd_init()) ++ ErrorF("[config] failed to initialise devd backend\n"); + } + + void +@@ -74,6 +76,7 @@ + #elif defined(CONFIG_WSCONS) + config_wscons_fini(); + #endif ++ config_devd_fini(); + } + + static void +--- hw/xfree86/common/xf86Config.c.orig 2013-09-20 00:07:58.000000000 +0300 ++++ hw/xfree86/common/xf86Config.c 2013-09-20 00:16:33.000000000 +0300 +@@ -1371,15 +1371,17 @@ + } + + if (!xf86Info.forceInputDevices && !(foundPointer && foundKeyboard)) { +-#if defined(CONFIG_HAL) || defined(CONFIG_UDEV) || defined(CONFIG_WSCONS) ++#if defined(CONFIG_HAL) || defined(CONFIG_UDEV) || defined(CONFIG_WSCONS) || 1 + const char *config_backend; + + #if defined(CONFIG_HAL) + config_backend = "HAL"; + #elif defined(CONFIG_UDEV) + config_backend = "udev"; +-#else ++#elif defined(CONFIG_WSCONS) + config_backend = "wscons"; ++#else ++ config_backend = "devd"; + #endif + xf86Msg(X_INFO, "The server relies on %s to provide the list of " + "input devices.\n\tIf no devices become available, " +--- hw/xfree86/common/xf86Globals.c.orig 2013-09-20 00:11:46.000000000 +0300 ++++ hw/xfree86/common/xf86Globals.c 2013-09-20 00:16:13.000000000 +0300 +@@ -122,7 +122,7 @@ + .log = LogNone, + .disableRandR = FALSE, + .randRFrom = X_DEFAULT, +-#if defined(CONFIG_HAL) || defined(CONFIG_UDEV) || defined(CONFIG_WSCONS) ++#if defined(CONFIG_HAL) || defined(CONFIG_UDEV) || defined(CONFIG_WSCONS) || 1 + .forceInputDevices = FALSE, + .autoAddDevices = TRUE, + .autoEnableDevices = TRUE diff -ruN xorg-server.orig/files/xhotplug.conf.in xorg-server/files/xhotplug.conf.in --- xorg-server.orig/files/xhotplug.conf.in 1970-01-01 03:00:00.000000000 +0300 +++ xorg-server/files/xhotplug.conf.in 2013-10-30 12:59:46.000000000 +0200 @@ -0,0 +1,22 @@ +attach 200 { + device-name "(joy|psm)[0-9]+"; + action "/usr/local/etc/rc.d/xhotplug add $device-name"; +}; +attach 200 { + device-name "(atp|uep|uhid)[0-9]+"; + action "/usr/local/etc/rc.d/xhotplug add/usb $device-name $port.$devaddr"; +}; +attach 200 { + device-name "ums[0-9]+"; + action "/etc/rc.d/moused quietstart $device-name"; + action "/usr/local/etc/rc.d/xhotplug add/usb $device-name $port.$devaddr"; +}; +detach 200 { + device-name "(atp|joy|psm|uep|uhid)[0-9]+"; + action "/usr/local/etc/rc.d/xhotplug remove $device-name"; +}; +detach 200 { + device-name "ums[0-9]+"; + action "/etc/rc.d/moused stop $device-name"; + action "/usr/local/etc/rc.d/xhotplug remove $device-name"; +}; diff -ruN xorg-server.orig/files/xhotplug.in xorg-server/files/xhotplug.in --- xorg-server.orig/files/xhotplug.in 1970-01-01 03:00:00.000000000 +0300 +++ xorg-server/files/xhotplug.in 2013-10-30 13:00:11.000000000 +0200 @@ -0,0 +1,143 @@ +#!/bin/sh +# +# PROVIDE: xhotplug +# REQUIRE: moused cleanvar + +devlist=/var/run/xorg-devpipe.list +devpipe=/var/run/xorg-devpipe.pipe + +fmt_options() { + /usr/bin/awk ' + function quote(str, suffix, i) { + sub("= +", "=", str); + sub(" +$", "", str); + match(str, "=.*") + if (RLENGTH <= 1) return + for (i = 1; i <= length(str); i++) { + c = substr(str, i, 1); + if (c ~ /[a-zA-Z0-9=:._-]/) { + printf "%s", c + } else { + printf "%%%02x", charmap[c] + } + } + } + BEGIN { + for(i = 0; i < 256; i++) + charmap[sprintf("%c", i)] = i + for (i = 1; i <= ARGC; i++) { + quote(ARGV[i]) + printf " " + } + }' "$@" +} + +driver_options() { + case "$1" in + *kbd*) printf "driver=kbd flags=keyboard ";; + atp*|psm*|ums*) printf "driver=mouse flags=pointer ";; + joy*) printf "flags=joystick ";; + uep*) printf "driver=egalax flags=touchscreen ";; + esac +} + +std_options() { + local desc + desc="`/sbin/sysctl -nq dev.${1%%[0-9]*}.${1##*[a-z]}.%desc`" + [ -n "${desc%%,*}" ] && fmt_options "name=${desc%%,*}" +} + +usb_options() { + local desc line nl product product_id vendor vendor_id + desc=`/usr/sbin/usbconfig -d "$1" dump_device_desc` + nl=`printf '\nx'` + nl=${nl%x} + while line=${desc%%$nl*}; do + case "$line" in + *idVendor\ =*) + vendor_id=${line#*= 0x} + vendor_id=${vendor_id% } + ;; + *idProduct\ =*) + product_id=${line#*= 0x} + product_id=${product_id% } + ;; + *iManufacturer\ =*) + vendor=${line#*<} + vendor=${vendor%>*} + [ "$vendor" = "no string" ] && vendor= + ;; + *iProduct\ =*) + product=${line#*<} + product=${product%>*} + [ "$product" = "no string" ] && product= + ;; + esac + [ "$desc" = "${desc#*$nl}" ] && break + desc=${desc#*$nl} + done + fmt_options \ + "usb_id=$vendor_id:$product_id" \ + "vendor=$vendor" \ + "product=$product" \ + "name=$vendor $product" +} + +send_message() { + for socket in "$devpipe"*; do + [ -S "$socket" ] && printf -- "%s" "$*" | /usr/bin/nc -w 5 -U "$socket" + done +} + +add_entry() { + printf "%s\n" "$*" >> "$devlist" + send_message "+$*" +} + +remove_entry() { + [ -f "$devlist" ] && /usr/bin/sed -EI '' "/^$1( |\$)/d" "$devlist" + send_message "-$1" +} + +case "$1" in +faststart|forcestart|onestart|quietstart|start) + add_entry syscons driver=kbd device= flags=keyboard \ + name=System%20Keyboard product=syscons + add_entry sysmouse driver=mouse flags=pointer \ + name=System%20Mouse product=sysmouse + ;; +faststop|forcestop|onestop|quietstop|stop) + rm -f "$devlist" + ;; +add) + device=$2 + shift 2 + add_entry "$device" \ + "`driver_options "$device"; std_options "$device"; fmt_options "$@"`" + ;; +add/usb) + device=$2 + usb=$3 + shift 3 + add_entry "$device" \ + "`driver_options "$device"; usb_options "$usb"; fmt_options "$@"`" + ;; +remove) + device=$2 + remove_entry "$device" + ;; +list) + [ -f "$devlist" ] && cat "$devlist" + ;; +*) + echo "unknown command: $*" 1>&2 + echo "usage:" 1>&2 + echo " $0 start" 1>&2 + echo " $0 stop" 1>&2 + echo " $0 add [