diff options
Diffstat (limited to 'libaxl_parse_display.c')
-rw-r--r-- | libaxl_parse_display.c | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/libaxl_parse_display.c b/libaxl_parse_display.c new file mode 100644 index 0000000..1b304e3 --- /dev/null +++ b/libaxl_parse_display.c @@ -0,0 +1,154 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +int +libaxl_parse_display(const char *name, char **hostp, char **protocolp, int *displayp, int *screenp) +{ + char *p; + size_t n; + unsigned long int ul; + int err; + int saved_errno = errno; + struct stat st; + + *hostp = NULL; + *protocolp = NULL; + *displayp = 0; + *screenp = 0; + + /* Get display server name string, if not specified */ + if (!name || !*name) { + name = getenv("DISPLAY"); + if (!name || !*name) { + liberror_save_backtrace(NULL); + liberror_set_error("No display server specified", "libaxl_parse_display", "libaxl", + LIBAXL_ERROR_NO_DISPLAY_SERVER_SPECIFIED); + err = LIBAXL_ERROR_NO_DISPLAY_SERVER_SPECIFIED; + goto fail; + } + } + + /* Get path and test if protocol is "unix" */ + p = strrchr(name, '.'); + if (p && isdigit(*p)) { + errno = 0; + ul = strtoul(p, &p, 10); + if (errno || ul > (unsigned long int)INT_MAX) + p = NULL; + else + *screenp = (int)ul; + } + n = p ? (size_t)(p - name) : strlen(name); + if (n) { + *hostp = liberror_malloc(n + 1); + if (!*hostp) + goto errno_fail; + memcpy(*hostp, name, n); + (*hostp)[n] = '\0'; + if (stat(*hostp, &st) || (st.st_mode & S_IFMT) != S_IFSOCK) { + free(*hostp); + *hostp = NULL; + goto normal; + } + *protocolp = liberror_malloc(sizeof("unix")); + if (!*protocolp) + goto errno_fail; + stpcpy(*protocolp, "unix"); + goto done; + } + +normal: + /* Get protocol */ + p = strrchr(name, '/'); + if (p) { + n = (size_t)(p - name); + *protocolp = liberror_malloc(n + 1); + if (*protocolp) + goto errno_fail; + memcpy(*protocolp, name, n); + (*protocolp)[n] = '\0'; + name = &p[1]; + } + + /* Get host */ + p = strrchr(name, ':'); + if (!p) { + liberror_save_backtrace(NULL); + liberror_set_error("Invalid display name: no display index", "libaxl_parse_display", "libaxl", + LIBAXL_ERROR_INVALID_DISPLAY_NAME_NO_DISPLAY_INDEX); + err = LIBAXL_ERROR_INVALID_DISPLAY_NAME_NO_DISPLAY_INDEX; + goto fail; + } else { + n = (size_t)(p - name); + *hostp = liberror_malloc(n + 1); + if (!*hostp) + goto errno_fail; + memcpy(*hostp, name, n); + (*hostp)[n] = '\0'; + name = &p[1]; + } + + /* Get display */ + if (!isdigit(*name)) { + liberror_save_backtrace(NULL); + liberror_set_error("Invalid display name: no display index", "libaxl_parse_display", "libaxl", + LIBAXL_ERROR_INVALID_DISPLAY_NAME_NO_DISPLAY_INDEX); + err = LIBAXL_ERROR_INVALID_DISPLAY_NAME_NO_DISPLAY_INDEX; + goto fail; + } + saved_errno = errno; + errno = 0; + ul = strtoul(name, (void *)&name, 10); + if (errno || ul > (unsigned long int)(*hostp ? 65535 - X_TCP_PORT : INT_MAX)) { + liberror_save_backtrace(NULL); + liberror_set_error("Invalid display name: display index is out of domain", "libaxl_parse_display", "libaxl", + LIBAXL_ERROR_INVALID_DISPLAY_NAME_DISPLAY_INDEX_OUT_OF_DOMAIN); + err = LIBAXL_ERROR_INVALID_DISPLAY_NAME_DISPLAY_INDEX_OUT_OF_DOMAIN; + goto fail; + } + *displayp = (int)ul; + errno = saved_errno; + + /* Get screen */ + if (*name) + goto done; + if (!isdigit(*name)) { + liberror_save_backtrace(NULL); + liberror_set_error("Invalid display name: invalid screen index", "libaxl_parse_display", "libaxl", + LIBAXL_ERROR_INVALID_DISPLAY_NAME_INVALID_SCREEN_INDEX); + err = LIBAXL_ERROR_INVALID_DISPLAY_NAME_INVALID_SCREEN_INDEX; + goto fail; + } + errno = 0; + ul = strtoul(name, (void *)&name, 10); + if (errno || ul > (unsigned long int)INT_MAX) { + liberror_save_backtrace(NULL); + liberror_set_error("Invalid display name: screen index is out of domain", "libaxl_parse_display", "libaxl", + LIBAXL_ERROR_INVALID_DISPLAY_NAME_SCREEN_INDEX_OUT_OF_DOMAIN); + err = LIBAXL_ERROR_INVALID_DISPLAY_NAME_SCREEN_INDEX_OUT_OF_DOMAIN; + goto fail; + } + *screenp = (int)ul; + if (*name) { + liberror_save_backtrace(NULL); + liberror_set_error("Invalid display name: invalid screen index", "libaxl_parse_display", "libaxl", + LIBAXL_ERROR_INVALID_DISPLAY_NAME_INVALID_SCREEN_INDEX); + err = LIBAXL_ERROR_INVALID_DISPLAY_NAME_INVALID_SCREEN_INDEX; + goto fail; + } + +done: + errno = saved_errno; + return 0; + +errno_fail: + err = LIBAXL_ERROR_SYSTEM; +fail: + free(*protocolp); + *protocolp = NULL; + free(*hostp); + *hostp = NULL; + if (err != LIBAXL_ERROR_SYSTEM) + errno = EINVAL; + return err; +} |