aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/lib/gamma-linux-drm.c135
1 files changed, 81 insertions, 54 deletions
diff --git a/src/lib/gamma-linux-drm.c b/src/lib/gamma-linux-drm.c
index cf98115..2619e0d 100644
--- a/src/lib/gamma-linux-drm.c
+++ b/src/lib/gamma-linux-drm.c
@@ -191,68 +191,95 @@ int libgamma_linux_drm_site_restore(libgamma_site_state_t* restrict this)
*/
static int figure_out_card_open_error(const char* pathname)
{
+ gid_t supplemental_groups[NGROUPS_MAX];
+ struct group* group;
+ 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 (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))
- gid_t supplemental_groups[NGROUPS_MAX];
- struct group* group;
- struct stat attr;
- int i, n;
-
-
- /* Get permission requirement for the file. */
- if (stat(pathname, &attr) < 0)
- 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 == 0 /* root group */ || __test(S_IRGRP, S_IWGRP))
- return LIBGAMMA_DEVICE_RESTRICTED;
-
-
- /* Get the user's supplemental group membership list. */
- if ((n = getgroups(NGROUPS_MAX, supplemental_groups)) < 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 = 0;
- group = getgrgid(attr.st_gid); /* TODO: Not thread-safe. */
- libgamma_group_gid = attr.st_gid;
- libgamma_group_name = group != NULL ? group->gr_name : NULL;
- return LIBGAMMA_DEVICE_REQUIRE_GROUP;
-#undef __test
- }
+ /* Get permission requirement for the file. */
+ if (stat(pathname, &attr) < 0)
+ 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 == 0 /* root group */ || __test(S_IRGRP, S_IWGRP))
+ return LIBGAMMA_DEVICE_RESTRICTED;
+
+
+ /* Get the user's supplemental group membership list. */
+ if ((n = getgroups(NGROUPS_MAX, supplemental_groups)) < 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. */
+#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE || _POSIX_SOURCE
+ /* Thread-safe. */
+ {
+ static __thread char buf[1024]; /* My output of `sysconf(_SC_GETGR_R_SIZE_MAX)`. */
+ struct group _grp;
+
+ 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;
+ }
+#else
+# ifdef __GCC__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wcpp"
+# warning figure_out_card_open_error is not thread-safe
+# pragma GCC diagnostic pop
+# endif
+ /* Not thread-safe. */
+ errno = 0;
+ group = getgrgid(attr.st_gid);
+#endif
- /* If we could not figure out what
- went wrong, just return the error
- we got. */
- return LIBGAMMA_ERRNO_SET;
+ libgamma_group_gid = attr.st_gid;
+ libgamma_group_name = group != NULL ? group->gr_name : NULL;
+ return LIBGAMMA_DEVICE_REQUIRE_GROUP;
+#undef __test
}