/* See LICENSE file for copyright and license details. */ #include "common.h" /** * Test whether a file descriptor refers to a VT * * @param fd The file descriptor * @return Whether the file descriptor refers to a VT */ static int is_vt_proper(int fd) { char buf[32], digit0; /* Get TTY */ if (ttyname_r(fd, buf, sizeof(buf) / sizeof(char))) return 0; /* Validate TTY path */ if (!strcmp(buf, "/dev/console")) return 1; if (strncmp(buf, "/dev/tty", sizeof("/dev/tty") - 1)) return 0; /* Validate TTY name */ digit0 = buf[sizeof("/dev/tty") - 1]; return '1' <= digit0 && digit0 <= '9'; } /** * Test the availability of an adjustment method * * @param method The adjustment method * @param operation Allowed values: * 0: Pass if the environment suggests it will work but is not fake * 1: Pass if the environment suggests it will work * 2: Pass if real and not fake * 3: Pass if real * 4: Always pass * Other values invoke undefined behaviour * @return Whether the test passed */ static int list_method_test(int method, int operation) { libgamma_method_capabilities_t caps; int fd, r, saved_errno; libgamma_method_capabilities(&caps, sizeof(caps), method); switch (operation) { case 0: /* Methods that the environment suggests will work, excluding fake */ if (caps.fake) return 0; /* fall through */ case 1: /* Methods that the environment suggests will work, including fake */ if (!caps.real) return 0; #ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM if (method == LIBGAMMA_METHOD_LINUX_DRM) { saved_errno = errno; if (is_vt_proper(STDIN_FILENO)) { r = 1; } else if (is_vt_proper(STDOUT_FILENO)) { r = 1; } else if (is_vt_proper(STDERR_FILENO)) { r = 1; } else { r = 0; fd = open("/dev/tty", O_RDONLY); if (fd >= 0) { r = is_vt_proper(fd); close(fd); } } errno = saved_errno; return r; } #endif #ifdef HAVE_LIBGAMMA_METHOD_DUMMY if (method == LIBGAMMA_METHOD_DUMMY) return 0; #endif return caps.default_site_known; case 2: /* All real non-fake methods */ return caps.real && !caps.fake; case 3: /* All real methods */ return caps.real; default: /* All methods */ return 1; } } /** * List available adjustment methods by their order of preference based on the environment * * @param methods Output array of methods, should be able to hold `LIBGAMMA_METHOD_COUNT` elements * @param buf_size The number of elements that fits in `methods`, it should be `LIBGAMMA_METHOD_COUNT`, * This is used to avoid writing outside the output buffer if this library adds new * adjustment methods without the users of the library recompiling * @param operation Allowed values: * 0: Methods that the environment suggests will work, excluding fake * 1: Methods that the environment suggests will work, including fake * 2: All real non-fake methods * 3: All real methods * 4: All methods * Other values invoke undefined behaviour * @return The number of element that have been stored in `methods`, or should * have been stored if the buffer was large enough */ size_t libgamma_list_methods(int *restrict methods, size_t buf_size, int operation) { size_t n = 0; #define X(CONST, ...)\ if (list_method_test(CONST, operation) && n++ < buf_size)\ methods[n - 1] = CONST; LIST_AVAILABLE_METHODS(X) #undef X return n; }