diff --git a/sycl/test/tools/Inputs/mock_renderd_access.c b/sycl/test/tools/Inputs/mock_renderd_access.c new file mode 100644 index 0000000000000..66cc41fea8bc4 --- /dev/null +++ b/sycl/test/tools/Inputs/mock_renderd_access.c @@ -0,0 +1,41 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +int stat(const char *pathname, struct stat *statbuf) { + const char *mock_mode = getenv("MOCK_STAT_MODE"); + if (strstr(pathname, "renderD128")) { + if (mock_mode && strcmp(mock_mode, "notfound") == 0) { + errno = ENOENT; + return -1; + } + if (mock_mode && strcmp(mock_mode, "exists") == 0) { + memset(statbuf, 0, sizeof(*statbuf)); + statbuf->st_mode = S_IFCHR | 0666; + return 0; + } + } + // Default: file does not exist + errno = ENOENT; + return -1; +} + +int open(const char *pathname, int flags, ...) { + const char *mock_mode = getenv("MOCK_OPEN_MODE"); + if (strstr(pathname, "renderD128")) { + if (mock_mode && strcmp(mock_mode, "deny") == 0) { + errno = EACCES; + return -1; + } + if (mock_mode && strcmp(mock_mode, "allow") == 0) { + return 3; // Dummy fd + } + } + // Default: permission denied + errno = EACCES; + return -1; +} diff --git a/sycl/test/tools/render-group.cpp b/sycl/test/tools/render-group.cpp new file mode 100644 index 0000000000000..0a26d09306f69 --- /dev/null +++ b/sycl/test/tools/render-group.cpp @@ -0,0 +1,21 @@ +// REQUIRES: linux + +// Compile Inputs/mock_renderd_access.c to a shared library and then use +// LD_PRELOAD to mock the stat and open functions. +// RUN: %clang -shared -fPIC -o %t-mock_stat.so %S/Inputs/mock_renderd_access.c + +// Check the case when /dev/dri/renderD128 does not exist. +// RUN: env MOCK_STAT_MODE=notfound LD_PRELOAD=%t-mock_stat.so sycl-ls --verbose --ignore-device-selectors 2>&1 | FileCheck %s -check-prefix=CHECK-NOTFOUND +// We don't expect any warning about permissions in this case. +// CHECK-NOTFOUND-NOT: WARNING: Unable to access /dev/dri/renderD128 due to permissions (EACCES). + +// Check the case when /dev/dri/renderD128 exists but is not accessible. +// RUN: env MOCK_STAT_MODE=exists MOCK_OPEN_MODE=deny LD_PRELOAD=%t-mock_stat.so sycl-ls --verbose --ignore-device-selectors 2>&1 | FileCheck %s --check-prefix=CHECK-DENY +// CHECK-DENY: WARNING: Unable to access /dev/dri/renderD128 due to permissions (EACCES). +// CHECK-DENY-NEXT: You might be missing the 'render' group locally. +// CHECK-DENY-NEXT: Try: sudo usermod -a -G render $USER +// CHECK-DENY-NEXT: Then log out and log back in. + +// Check the case when /dev/dri/renderD128 exists and is accessible. +// RUN: env MOCK_STAT_MODE=exists MOCK_OPEN_MODE=allow LD_PRELOAD=%t-mock_stat.so sycl-ls --verbose --ignore-device-selectors 2>&1 | FileCheck %s --check-prefix=CHECK-GRANT +// CHECK-GRANT-NOT: WARNING: Unable to access /dev/dri/renderD128 due to permissions (EACCES). diff --git a/sycl/tools/sycl-ls/sycl-ls.cpp b/sycl/tools/sycl-ls/sycl-ls.cpp index 32de5b3e6d213..202e7b7e1c219 100644 --- a/sycl/tools/sycl-ls/sycl-ls.cpp +++ b/sycl/tools/sycl-ls/sycl-ls.cpp @@ -26,6 +26,13 @@ #include #include +#ifdef __linux__ +#include +#include +#include +#include +#include +#endif #ifdef _WIN32 #include #include @@ -344,8 +351,30 @@ static int unsetFilterEnvVarsAndFork() { } #endif -int main(int argc, char **argv) { +static void checkRenderGroupPermission() { +#ifdef __linux__ + // Check for /dev/dri/render* devices + for (int i = 128; i < 256; ++i) { + std::string path = std::string("/dev/dri/renderD") + std::to_string(i); + struct stat st; + if (stat(path.c_str(), &st) == 0) { + int fd = open(path.c_str(), O_RDWR); + if (fd < 0 && errno == EACCES) { + std::cerr << "WARNING: Unable to access " << path + << " due to permissions (EACCES).\n" + << "You might be missing the 'render' group locally.\n" + << "Try: sudo usermod -a -G render $USER\n" + << "Then log out and log back in.\n"; + break; + } + if (fd >= 0) + close(fd); + } + } +#endif +} +int main(int argc, char **argv) { if (argc == 1) { verbose = false; DiscardFilters = false; @@ -361,6 +390,9 @@ int main(int argc, char **argv) { } } + if (verbose) + checkRenderGroupPermission(); + bool SuppressNumberPrinting = false; // Print warning and suppress printing device ids if any of // the filter environment variable is set.