Index: xorg-server/files/extra-new-devd =================================================================== --- xorg-server/files/extra-new-devd +++ xorg-server/files/extra-new-devd @@ -1,6 +1,5 @@ ---- config/devd.c.orig 2014-09-09 21:28:03.646653866 +0200 -+++ config/devd.c 2014-09-09 22:39:39.978360587 +0200 -@@ -0,0 +1,432 @@ +Index: config/devd.c +@@ -0,0 +1,472 @@ +/* + * Copyright (c) 2012 Baptiste Daroussin + * Copyright (c) 2013, 2014 Alex Kozlov @@ -59,8 +58,11 @@ +#define DEVD_EVENT_ADD '+' +#define DEVD_EVENT_REMOVE '-' + -+static int sock_devd = -1; ++#define RECONNECT_DELAY 5 * 1000 + ++static int sock_devd; ++OsTimerPtr rtimer; ++ +struct hw_type { + const char *driver; + int flag; @@ -73,7 +75,6 @@ + { "sysmouse", ATTR_POINTER, "mouse" }, + { "ums", ATTR_POINTER, "mouse" }, + { "psm", ATTR_POINTER, "mouse" }, -+ { "uhid", ATTR_POINTER, "mouse" }, + { "joy", ATTR_JOYSTICK, NULL }, + { "atp", ATTR_TOUCHPAD, NULL }, + { "uep", ATTR_TOUCHSCREEN, NULL }, @@ -82,56 +83,56 @@ + +static bool +sysctl_exists(const struct hw_type *device, int unit, -+ char *devname, size_t devname_len) ++ char *devname, size_t devname_len) +{ -+ char *sysctlname; -+ size_t len; -+ int ret; ++ char *sysctlname; ++ size_t len; ++ int ret; + -+ if (device == NULL || device->driver == NULL) -+ return false; ++ if (device == NULL || device->driver == NULL) ++ return false; + -+ /* Check if a sysctl exists. */ -+ asprintf(&sysctlname, "dev.%s.%i.%%desc", device->driver, unit); -+ if (sysctlname == NULL) -+ return (0); ++ /* Check if a sysctl exists. */ ++ asprintf(&sysctlname, "dev.%s.%i.%%desc", device->driver, unit); ++ if (sysctlname == NULL) ++ return false; + -+ ret = sysctlbyname(sysctlname, NULL, &len, NULL, 0); -+ free(sysctlname); ++ ret = sysctlbyname(sysctlname, NULL, &len, NULL, 0); ++ free(sysctlname); + -+ if (ret == 0 && len > 0) { -+ snprintf(devname, devname_len, "%s%i", device->driver, unit); -+ return (1); -+ } ++ if (ret == 0 && len > 0) { ++ snprintf(devname, devname_len, "%s%i", device->driver, unit); ++ return true; ++ } + -+ return (0); ++ return false; +} + +static bool +devpath_exists(const struct hw_type *device, -+ char *devname, size_t devname_len) ++ char *devname, size_t devname_len) +{ -+ char *devpath; -+ struct stat st; -+ int ret; ++ char *devpath; ++ struct stat st; ++ int ret; + -+ if (device == NULL || device->driver == NULL) -+ return false; ++ if (device == NULL || device->driver == NULL) ++ return false; + -+ /* Check if /dev/$driver exists. */ -+ asprintf(&devpath, "/dev/%s", device->driver); -+ if (devpath == NULL) -+ return (0); ++ /* Check if /dev/$driver exists. */ ++ asprintf(&devpath, "/dev/%s", device->driver); ++ if (devpath == NULL) ++ return false; + -+ ret = stat(devpath, &st); -+ free(devpath); ++ ret = stat(devpath, &st); ++ free(devpath); + -+ if (ret == 0) { -+ strncpy(devname, device->driver, devname_len); -+ return (1); -+ } ++ if (ret == 0) { ++ strncpy(devname, device->driver, devname_len); ++ return true; ++ } + -+ return (0); ++ return false; +} + +static char * @@ -151,17 +152,16 @@ + + if (sysctlbyname(name, NULL, &len, NULL, 0) == 0) { + dest = malloc(len + 1); -+ if (!dest) -+ goto unwind; -+ if (sysctlbyname(name, dest, &len, NULL, 0) == 0) -+ dest[len] = '\0'; -+ else { -+ free(dest); -+ dest = NULL; ++ if (dest) { ++ if (sysctlbyname(name, dest, &len, NULL, 0) == 0) ++ dest[len] = '\0'; ++ else { ++ free(dest); ++ dest = NULL; ++ } + } + } + -+ unwind: + free(name); + return dest; +} @@ -169,132 +169,183 @@ +static void +device_added(char *devname) +{ -+ char path[PATH_MAX]; -+ char *vendor; -+ char *product = NULL; -+ char *config_info = NULL; -+ char *walk; -+ InputOption *options = NULL; -+ InputAttributes attrs = { }; -+ DeviceIntPtr dev = NULL; -+ int i, rc; -+ int fd; ++ char path[PATH_MAX]; ++ char *vendor; ++ char *product = NULL; ++ char *config_info = NULL; ++ char *walk; ++ InputOption *options = NULL; ++ InputAttributes attrs = { }; ++ DeviceIntPtr dev = NULL; ++ int i; ++ int fd; + -+ for (i = 0; hw_types[i].driver != NULL; i++) { -+ size_t len; ++ for (i = 0; hw_types[i].driver != NULL; i++) { ++ size_t len; + -+ len = strlen(hw_types[i].driver); -+ if (strcmp(devname, hw_types[i].driver) == 0 || -+ (strncmp(devname, hw_types[i].driver, len) == 0 && -+ isnumber(*(devname + len)))) { -+ attrs.flags |= hw_types[i].flag; -+ break; -+ } -+ } -+ if (hw_types[i].driver == NULL) { -+ LogMessageVerb(X_INFO, 10, "config/devd: ignoring device %s\n", -+ devname); -+ return; -+ } -+ if (hw_types[i].xdriver == NULL) { -+ LogMessageVerb(X_INFO, 10, "config/devd: ignoring device %s\n", -+ devname); -+ return; -+ } -+ snprintf(path, sizeof(path), "/dev/%s", devname); ++ len = strlen(hw_types[i].driver); ++ if (strcmp(devname, hw_types[i].driver) == 0 || ++ (strncmp(devname, hw_types[i].driver, len) == 0 && ++ isnumber(*(devname + len)))) { ++ attrs.flags |= hw_types[i].flag; ++ break; ++ } ++ } + -+ options = input_option_new(NULL, "_source", "server/devd"); -+ if (!options) -+ return; ++ if (hw_types[i].driver == NULL || hw_types[i].xdriver == NULL) { ++ LogMessage(X_INFO, 10, "config/devd: ignoring device %s\n", ++ devname); ++ return; ++ } + -+ vendor = -+ sysctl_get_str("dev.%s.%s.%%desc", hw_types[i].driver, -+ devname + strlen(hw_types[i].driver)); -+ if (vendor == NULL) { -+ attrs.vendor = strdup("(unnamed)"); -+ attrs.product = strdup("(unnamed)"); -+ options = input_option_new(options, "name", devname); -+ } -+ else { -+ if ((walk = strchr(vendor, ' ')) != NULL) { -+ walk[0] = '\0'; -+ walk++; -+ product = walk; -+ if ((walk = strchr(product, ',')) != NULL) -+ walk[0] = '\0'; -+ } ++ snprintf(path, sizeof(path), "/dev/%s", devname); + -+ attrs.vendor = strdup(vendor); -+ if (product) -+ attrs.product = strdup(product); -+ else -+ attrs.product = strdup("(unnamed)"); ++ options = input_option_new(NULL, "_source", "server/devd"); ++ if (!options) ++ return; + -+ options = input_option_new(options, "name", xstrdup(attrs.product)); ++ vendor = sysctl_get_str("dev.%s.%s.%%desc", hw_types[i].driver, ++ devname + strlen(hw_types[i].driver)); ++ if (vendor == NULL) { ++ attrs.vendor = strdup("(unnamed)"); ++ attrs.product = strdup("(unnamed)"); ++ options = input_option_new(options, "name", devname); ++ } ++ else { ++ if ((walk = strchr(vendor, ' ')) != NULL) { ++ walk[0] = '\0'; ++ walk++; ++ product = walk; ++ if ((walk = strchr(product, ',')) != NULL) ++ walk[0] = '\0'; ++ } + -+ free(vendor); -+ } -+ attrs.usb_id = NULL; -+ attrs.device = strdup(path); -+ options = input_option_new(options, "driver", hw_types[i].xdriver); -+ if (attrs.flags & ATTR_KEYBOARD) { -+ /* -+ * Don't pass device option if keyboard is attached to console (open fails), -+ * thus activating special logic in xf86-input-keyboard. -+ */ -+ fd = open(path, O_RDONLY | O_NONBLOCK | O_EXCL); -+ if (fd > 0) { -+ close(fd); -+ options = input_option_new(options, "device", xstrdup(path)); -+ } -+ } ++ attrs.vendor = strdup(vendor); ++ if (product) ++ attrs.product = strdup(product); ++ else ++ attrs.product = strdup("(unnamed)"); ++ ++ options = input_option_new(options, "name", xstrdup(attrs.product)); ++ ++ free(vendor); ++ } ++ ++ /* XXX implement usb_id */ ++ attrs.usb_id = NULL; ++ attrs.device = strdup(path); ++ options = input_option_new(options, "driver", hw_types[i].xdriver); ++ ++ fd = open(path, O_RDONLY | O_NONBLOCK | O_EXCL); ++ if (fd > 0) { ++ close(fd); ++ options = input_option_new(options, "device", xstrdup(path)); ++ } + else { -+ options = input_option_new(options, "device", xstrdup(path)); -+ } ++ /* ++ * Don't pass "device" option if the device is a keyboard and is ++ * already attached to the console (ie. open() fails). ++ * This would activate a special logic in xf86-input-keyboard. ++ */ ++ if (attrs.flags & ~ATTR_KEYBOARD) { ++ options = input_option_new(options, "device", xstrdup(path)); ++ } ++ LogMessage(X_WARNING, "config/devd: device %s already opened\n", ++ path); ++ } + -+ if (asprintf(&config_info, "devd:%s", devname) == -1) { -+ config_info = NULL; -+ goto unwind; -+ } ++ if (asprintf(&config_info, "devd:%s", devname) == -1) { ++ config_info = NULL; ++ goto unwind; ++ } + -+ if (device_is_duplicate(config_info)) { -+ LogMessage(X_WARNING, "config/devd: device %s already added. " -+ "Ignoring.\n", attrs.product); -+ goto unwind; -+ } ++ if (device_is_duplicate(config_info)) { ++ LogMessage(X_WARNING, "config/devd: device %s already added. " ++ "Ignoring\n", attrs.product); ++ goto unwind; ++ } + -+ options = input_option_new(options, "config_info", config_info); -+ LogMessage(X_INFO, "config/devd: adding input device %s (%s)\n", -+ attrs.product, path); ++ options = input_option_new(options, "config_info", config_info); ++ LogMessage(X_INFO, "config/devd: adding input device %s (%s)\n", ++ attrs.product, path); + -+ rc = NewInputDeviceRequest(options, &attrs, &dev); ++ NewInputDeviceRequest(options, &attrs, &dev); + -+ if (rc != Success) -+ goto unwind; ++unwind: ++ free(config_info); ++ input_option_free_list(&options); + -+ unwind: -+ free(config_info); -+ input_option_free_list(&options); -+ -+ free(attrs.usb_id); -+ free(attrs.product); -+ free(attrs.device); -+ free(attrs.vendor); ++ free(attrs.usb_id); ++ free(attrs.product); ++ free(attrs.device); ++ free(attrs.vendor); +} + +static void +device_removed(char *devname) +{ -+ char *value; ++ char *value; + -+ if (asprintf(&value, "devd:%s", devname) == -1) -+ return; ++ if (asprintf(&value, "devd:%s", devname) == -1) ++ return; + -+ remove_devices("devd", value); ++ remove_devices("devd", value); + -+ free(value); ++ free(value); +} + ++static void ++disconnect_devd(int sock) ++{ ++ if (sock >= 0) { ++ RemoveGeneralSocket(sock); ++ close(sock); ++ } ++} ++ ++static int ++connect_devd(void) ++{ ++ struct sockaddr_un devd; ++ int sock; ++ ++ sock = socket(AF_UNIX, SOCK_STREAM, 0); ++ if (sock < 0) { ++ LogMessage(X_ERROR, "config/devd: fail opening stream socket\n"); ++ return -1; ++ } ++ ++ devd.sun_family = AF_UNIX; ++ strlcpy(devd.sun_path, DEVD_SOCK_PATH, sizeof(devd.sun_path)); ++ ++ if (connect(sock, (struct sockaddr *) &devd, sizeof(devd)) < 0) { ++ close(sock); ++ LogMessage(X_ERROR, "config/devd: fail to connect to devd\n"); ++ return -1; ++ } ++ ++ AddGeneralSocket(sock); ++ ++ return sock; ++} ++ ++static CARD32 ++reconnect_handler(OsTimerPtr timer, CARD32 time, pointer arg) ++{ ++ int newsock; ++ ++ if ((newsock = connect_devd()) > 0) { ++ sock_devd = newsock; ++ TimerFree(rtimer); ++ rtimer = NULL; ++ LogMessage(X_INFO, "config/devd: reopening devd socket\n"); ++ return 0; ++ } ++ ++ /* try again after RECONNECT_DELAY */ ++ return RECONNECT_DELAY; ++} ++ +static ssize_t +socket_getline(int fd, char **out) +{ @@ -309,13 +360,18 @@ + + for (;;) { + ret = read(sock_devd, &c, 1); -+ if (ret < 1) { ++ if (ret < 0) { + if (errno == EINTR) + continue; + free(buf); + return -1; ++ /* EOF - devd socket is lost */ ++ } else if (ret == 0) { ++ disconnect_devd(sock_devd); ++ rtimer = TimerSet(NULL, 0, 1, reconnect_handler, NULL); ++ LogMessage(X_WARNING, "config/devd: devd socket is lost\n"); ++ return -1; + } -+ + if (c == '\n') + break; + @@ -338,38 +394,39 @@ + else + free(buf); + -+ return sz; /* number of bytes in the line, not counting the line break */ ++ /* number of bytes in the line, not counting the line break */ ++ return sz; +} + +static void +wakeup_handler(void *data, int err, void *read_mask) +{ -+ char *line = NULL; -+ char *walk; ++ char *line = NULL; ++ char *walk; + -+ if (err < 0) -+ return; ++ if (err < 0) ++ return; + -+ if (FD_ISSET(sock_devd, (fd_set *) read_mask)) { -+ if (socket_getline(sock_devd, &line) < 0) -+ return; ++ if (FD_ISSET(sock_devd, (fd_set *) read_mask)) { ++ if (socket_getline(sock_devd, &line) < 0) ++ return; + -+ walk = strchr(line + 1, ' '); -+ if (walk != NULL) -+ walk[0] = '\0'; ++ walk = strchr(line + 1, ' '); ++ if (walk != NULL) ++ walk[0] = '\0'; + -+ switch (*line) { -+ case DEVD_EVENT_ADD: -+ device_added(line + 1); -+ break; -+ case DEVD_EVENT_REMOVE: -+ device_removed(line + 1); -+ break; -+ default: -+ break; -+ } -+ free(line); -+ } ++ switch (*line) { ++ case DEVD_EVENT_ADD: ++ device_added(line + 1); ++ break; ++ case DEVD_EVENT_REMOVE: ++ device_removed(line + 1); ++ break; ++ default: ++ break; ++ } ++ free(line); ++ } +} + +static void @@ -380,56 +437,38 @@ +int +config_devd_init(void) +{ -+ struct sockaddr_un devd; -+ char devicename[1024]; -+ int i, j, ret; ++ 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; j < 16; j++) { -+ ret = sysctl_exists(&hw_types[i], j, -+ devicename, sizeof(devicename)); -+ if (!ret) -+ continue; ++ for (i = 0; hw_types[i].driver != NULL; i++) { ++ /* first scan the sysctl to determine the hardware */ ++ for (j = 0; j < 16; j++) { ++ if (sysctl_exists(&hw_types[i], j, ++ devicename, sizeof(devicename)) != 0) ++ device_added(devicename); ++ } + -+ device_added(devicename); -+ } ++ if (devpath_exists(&hw_types[i], devicename, sizeof(devicename)) != 0) ++ device_added(devicename); ++ } + -+ ret = devpath_exists(&hw_types[i], devicename, sizeof(devicename)); -+ if (!ret) -+ continue; ++ if ((sock_devd = connect_devd()) < 0) ++ return 0; + -+ device_added(devicename); -+ } ++ RegisterBlockAndWakeupHandlers(block_handler, wakeup_handler, NULL); + -+ 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(devd)) < 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; ++ return 1; +} + +void +config_devd_fini(void) +{ -+ if (sock_devd < 0) -+ return; ++ if (rtimer) { ++ TimerFree(rtimer); ++ rtimer = NULL; ++ } + -+ RemoveGeneralSocket(sock_devd); -+ RemoveBlockAndWakeupHandlers(block_handler, wakeup_handler, NULL); -+ close(sock_devd); ++ disconnect_devd(sock_devd); ++ ++ RemoveBlockAndWakeupHandlers(block_handler, wakeup_handler, NULL); +}