aboutsummaryrefslogtreecommitdiffstats
path: root/libgamma_linux_drm_partition_initialise.c
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2021-03-05 18:23:13 +0100
committerMattias Andrée <maandree@kth.se>2021-03-05 18:33:49 +0100
commitf52513b09580c1533e6c48a4162d3d5f61f3b081 (patch)
tree141d0974a777f4ec5b51daed9879a2cb0d781505 /libgamma_linux_drm_partition_initialise.c
parentSplit source files, merge public header files, eliminite use gpp, rewrite makefile (diff)
downloadlibgamma-f52513b09580c1533e6c48a4162d3d5f61f3b081.tar.gz
libgamma-f52513b09580c1533e6c48a4162d3d5f61f3b081.tar.bz2
libgamma-f52513b09580c1533e6c48a4162d3d5f61f3b081.tar.xz
misc
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to 'libgamma_linux_drm_partition_initialise.c')
-rw-r--r--libgamma_linux_drm_partition_initialise.c151
1 files changed, 151 insertions, 0 deletions
diff --git a/libgamma_linux_drm_partition_initialise.c b/libgamma_linux_drm_partition_initialise.c
new file mode 100644
index 0000000..02cfffc
--- /dev/null
+++ b/libgamma_linux_drm_partition_initialise.c
@@ -0,0 +1,151 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+/**
+ * Figure out why `open` failed for a graphics card
+ *
+ * @param pathname The pathname of the error card
+ * @return The error code to report
+ */
+static int
+figure_out_card_open_error(const char *pathname)
+{
+ char buf[1024]; /* My output of `sysconf(_SC_GETGR_R_SIZE_MAX)`. */
+ gid_t supplemental_groups[NGROUPS_MAX];
+ struct group *group, _grp;
+ struct stat attr;
+ int i, n;
+
+
+ /* Check which the device exists */
+ if (errno == ENXIO || errno == ENODEV)
+ return LIBGAMMA_NO_SUCH_PARTITION;
+
+
+ /* If we did not get access permission, figure out why */
+
+ if (errno != EACCES) {
+ /* If we could not figure out what went
+ * wrong, just return the error we got */
+ return LIBGAMMA_ERRNO_SET;
+ }
+
+#define __test(R, W) ((attr.st_mode & ((R) | (W))) == ((R) | (W)))
+
+ /* Get permission requirement for the file */
+ if (stat(pathname, &attr))
+ return errno == EACCES ? LIBGAMMA_NO_SUCH_PARTITION : LIBGAMMA_ERRNO_SET;
+
+ /* Test owner's, group's and others' permissions */
+ if ((attr.st_uid == geteuid() && __test(S_IRUSR, S_IWUSR)) ||
+ (attr.st_gid == getegid() && __test(S_IRGRP, S_IWGRP)) || __test(S_IROTH, S_IWOTH))
+ return LIBGAMMA_DEVICE_ACCESS_FAILED;
+
+ /* The group should be "video", but perhaps
+ it is "root" to restrict users */
+ if (!attr.st_gid /* root group */ || __test(S_IRGRP, S_IWGRP))
+ return LIBGAMMA_DEVICE_RESTRICTED;
+
+
+ /* Get the user's supplemental group membership list */
+ n = getgroups(NGROUPS_MAX, supplemental_groups);
+ if (n < 0)
+ return LIBGAMMA_ERRNO_SET;
+
+ /* Test whether any of the supplemental
+ group should be satisfactory */
+ for (i = 0; i < n; i++)
+ if (supplemental_groups[i] == attr.st_gid)
+ break;
+
+ /* If one of the supplemental groups should be satisfactory,
+ then we do not know anything more than that access failed */
+ if (i != n)
+ return LIBGAMMA_DEVICE_ACCESS_FAILED;
+
+ /* Otherwise, try to get the name of the group that is
+ required and report the missing group membership */
+ errno = getgrgid_r(attr.st_gid, &_grp, buf, sizeof(buf) / sizeof(char), &group);
+ if (errno == ERANGE) {
+ /* The lenght of the group's name is absurdly long, degrade to thread-unsafe. */
+ errno = 0;
+ group = getgrgid(attr.st_gid);
+ } else if (errno) {
+ return LIBGAMMA_ERRNO_SET;
+ }
+
+ libgamma_group_gid_set(attr.st_gid);
+ libgamma_group_name_set(group ? group->gr_name : NULL);
+ return LIBGAMMA_DEVICE_REQUIRE_GROUP;
+#undef __test
+}
+
+
+/**
+ * Initialise an allocated partition state
+ *
+ * @param this The partition state to initialise
+ * @param site The site state for the site that the partition belongs to
+ * @param partition The the index of the partition within the site
+ * @return Zero on success, otherwise (negative) the value of an
+ * error identifier provided by this library
+ */
+int
+libgamma_linux_drm_partition_initialise(libgamma_partition_state_t *restrict this,
+ libgamma_site_state_t *restrict site, size_t partition)
+{
+ int rc = 0;
+ libgamma_drm_card_data_t *restrict data;
+ char pathname[PATH_MAX];
+
+ (void) site;
+
+ /* Check for partition index overflow */
+ if (partition > INT_MAX)
+ return LIBGAMMA_NO_SUCH_PARTITION;
+
+ /* Allocate and initialise graphics card data */
+ this->data = NULL;
+ data = malloc(sizeof(libgamma_drm_card_data_t));
+ if (!data)
+ return LIBGAMMA_ERRNO_SET;
+ data->fd = -1;
+ data->res = NULL;
+ data->encoders = NULL;
+ data->connectors = NULL;
+
+ /* Get the pathname for the graphics card */
+ snprintf(pathname, sizeof(pathname) / sizeof(char), DRM_DEV_NAME, DRM_DIR_NAME, (int)partition);
+
+ /* Acquire access to the graphics card */
+ data->fd = open(pathname, O_RDWR | O_CLOEXEC);
+ if (data->fd < 0) {
+ rc = figure_out_card_open_error(pathname);
+ goto fail_data;
+ }
+
+ /* Acquire mode resources */
+ data->res = drmModeGetResources(data->fd);
+ if (!data->res) {
+ rc = LIBGAMMA_ACQUIRING_MODE_RESOURCES_FAILED;
+ goto fail_fd;
+ }
+
+ /* Get the number of CRTC:s that are available in the partition */
+ if (data->res->count_crtcs < 0) {
+ rc = LIBGAMMA_NEGATIVE_CRTC_COUNT;
+ goto fail_res;
+ }
+ this->crtcs_available = (size_t)data->res->count_crtcs;
+ this->data = data;
+ return 0;
+
+fail_res:
+ drmModeFreeResources(data->res);
+fail_fd:
+ close(data->fd);
+fail_data:
+ free(data);
+ return rc;
+}