ports/183478: x11-servers/xorg-server: DEVD backend is broken, here's a fix

Vitaly Magerya vmagerya at gmail.com
Wed Oct 30 12:10:00 UTC 2013


>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 <bsd.port.options.mk>
@@ -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 <dix-config.h>
+#endif
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#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 <bapt at FreeBSD.org>
-+ */
-+
-+#ifdef HAVE_DIX_CONFIG_H
-+#include <dix-config.h>
-+#endif
-+
-+#include <sys/types.h>
-+#include <sys/socket.h>
-+#include <sys/sysctl.h>
-+#include <sys/un.h>
-+
-+#include <ctype.h>
-+#include <stdlib.h>
-+#include <stdio.h>
-+#include <stdarg.h>
-+#include <stdbool.h>
-+#include <unistd.h>
-+
-+#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 <devname> [<option>=<value> ...]" 1>&2
+    echo "  $0 add/usb <devname> <busnum>.<devaddr> [<option>=<value> ...]" 1>&2
+    echo "  $0 remove <devname>" 1>&2
+    echo "  $0 list" 1>&2
+    exit 1
+    ;;
+esac
diff -ruN xorg-server.orig/pkg-plist xorg-server/pkg-plist
--- xorg-server.orig/pkg-plist	2013-05-25 17:37:02.000000000 +0300
+++ xorg-server/pkg-plist	2013-10-30 13:00:40.000000000 +0200
@@ -2,6 +2,8 @@
 bin/Xorg
 bin/cvt
 bin/gtf
+%%DEVD%%etc/devd/xhotplug.conf
+%%DEVD%%etc/rc.d/xhotplug
 include/xorg/BT.h
 include/xorg/IBM.h
 include/xorg/TI.h


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-ports-bugs mailing list