/* 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 = -1;
/* 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;
}