github.com/tompreston/snapd@v0.0.0-20210817193607-954edfcb9611/cmd/snap-confine/mount-support-nvidia.c (about) 1 /* 2 * Copyright (C) 2015 Canonical Ltd 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 3 as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 * 16 */ 17 18 #include "config.h" 19 #include "mount-support-nvidia.h" 20 21 #include <errno.h> 22 #include <fcntl.h> 23 #include <glob.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <sys/mount.h> 27 #include <sys/stat.h> 28 #include <sys/types.h> 29 #include <stdint.h> 30 #include <unistd.h> 31 /* POSIX version of basename() and dirname() */ 32 #include <libgen.h> 33 34 #include "../libsnap-confine-private/classic.h" 35 #include "../libsnap-confine-private/cleanup-funcs.h" 36 #include "../libsnap-confine-private/string-utils.h" 37 #include "../libsnap-confine-private/utils.h" 38 39 #define SC_NVIDIA_DRIVER_VERSION_FILE "/sys/module/nvidia/version" 40 41 // note: if the parent dir changes to something other than 42 // the current /var/lib/snapd/lib then sc_mkdir_and_mount_and_bind 43 // and sc_mkdir_and_mount_and_bind need updating. 44 #define SC_LIB "/var/lib/snapd/lib" 45 #define SC_LIBGL_DIR SC_LIB "/gl" 46 #define SC_LIBGL32_DIR SC_LIB "/gl32" 47 #define SC_VULKAN_DIR SC_LIB "/vulkan" 48 #define SC_GLVND_DIR SC_LIB "/glvnd" 49 50 #define SC_VULKAN_SOURCE_DIR "/usr/share/vulkan" 51 #define SC_EGL_VENDOR_SOURCE_DIR "/usr/share/glvnd" 52 53 // Location for NVIDIA vulkan files (including _wayland) 54 static const char *vulkan_globs[] = { 55 "icd.d/*nvidia*.json", 56 }; 57 58 static const size_t vulkan_globs_len = 59 sizeof vulkan_globs / sizeof *vulkan_globs; 60 61 // Location of EGL vendor files 62 static const char *egl_vendor_globs[] = { 63 "egl_vendor.d/*nvidia*.json", 64 }; 65 66 static const size_t egl_vendor_globs_len = 67 sizeof egl_vendor_globs / sizeof *egl_vendor_globs; 68 69 #if defined(NVIDIA_BIARCH) || defined(NVIDIA_MULTIARCH) 70 71 // List of globs that describe nvidia userspace libraries. 72 // This list was compiled from the following packages. 73 // 74 // https://www.archlinux.org/packages/extra/x86_64/nvidia-304xx-libgl/files/ 75 // https://www.archlinux.org/packages/extra/x86_64/nvidia-304xx-utils/files/ 76 // https://www.archlinux.org/packages/extra/x86_64/nvidia-340xx-libgl/files/ 77 // https://www.archlinux.org/packages/extra/x86_64/nvidia-340xx-utils/files/ 78 // https://www.archlinux.org/packages/extra/x86_64/nvidia-libgl/files/ 79 // https://www.archlinux.org/packages/extra/x86_64/nvidia-utils/files/ 80 // 81 // FIXME: this doesn't yet work with libGLX and libglvnd redirector 82 // FIXME: this still doesn't work with the 361 driver 83 static const char *nvidia_globs[] = { 84 "libEGL.so*", 85 "libEGL_nvidia.so*", 86 "libGL.so*", 87 "libOpenGL.so*", 88 "libGLESv1_CM.so*", 89 "libGLESv1_CM_nvidia.so*", 90 "libGLESv2.so*", 91 "libGLESv2_nvidia.so*", 92 "libGLX_indirect.so*", 93 "libGLX_nvidia.so*", 94 "libGLX.so*", 95 "libGLdispatch.so*", 96 "libGLU.so*", 97 "libXvMCNVIDIA.so*", 98 "libXvMCNVIDIA_dynamic.so*", 99 "libnvidia-cfg.so*", 100 "libnvidia-compiler.so*", 101 "libnvidia-eglcore.so*", 102 "libnvidia-egl-wayland*", 103 "libnvidia-encode.so*", 104 "libnvidia-fatbinaryloader.so*", 105 "libnvidia-fbc.so*", 106 "libnvidia-glcore.so*", 107 "libnvidia-glsi.so*", 108 "libnvidia-glvkspirv.so*", 109 "libnvidia-ifr.so*", 110 "libnvidia-ml.so*", 111 "libnvidia-opencl.so*", 112 "libnvidia-opticalflow.so*", 113 "libnvidia-ptxjitcompiler.so*", 114 "libnvidia-rtcore.so*", 115 "libnvidia-tls.so*", 116 "libnvoptix.so*", 117 "tls/libnvidia-tls.so*", 118 "vdpau/libvdpau_nvidia.so*", 119 120 // additional libraries for Tegra 121 // https://docs.nvidia.com/jetson/l4t/index.html#page/Tegra%20Linux%20Driver%20Package%20Development%20Guide/manifest_tx2_tx2i.html 122 "libnvdc.so*", 123 "libnvos.so*", 124 "libnvrm_gpu.so*", 125 "libnvimp.so*", 126 "libnvrm.so*", 127 "libnvrm_graphics.so*", 128 // CUDA 129 // https://docs.nvidia.com/cuda/#cuda-api-references 130 "libcuda.so*", 131 "libcudart.so*", 132 "libnvcuvid.so*", 133 "libcufft.so*", 134 "libcublas.so*", 135 "libcublasLt.so*", 136 "libcusolver.so*", 137 "libcuparse.so*", 138 "libcurand.so*", 139 "libnppc.so*", 140 "libnppig.so*", 141 "libnppial.so*", 142 "libnppicc.so*", 143 "libnppidei.so*", 144 "libnppist.so*", 145 "libnppcif.so*", 146 "libnppim.so*", 147 "libnppitc.so*", 148 "libnvrtc*", 149 "libnvrtc-builtins*", 150 "libnvToolsExt.so*", 151 // libraries for CUDA DNN 152 // https://docs.nvidia.com/deeplearning/cudnn/api/index.html 153 // https://docs.nvidia.com/deeplearning/cudnn/install-guide/index.html 154 "libcudnn_adv_infer*", 155 "libcudnn_adv_train*", 156 "libcudnn_cnn_infer*", 157 "libcudnn_cnn_train*", 158 "libcudnn_ops_infer*", 159 "libcudnn_ops_train*", 160 }; 161 162 static const size_t nvidia_globs_len = 163 sizeof nvidia_globs / sizeof *nvidia_globs; 164 165 #endif // defined(NVIDIA_BIARCH) || defined(NVIDIA_MULTIARCH) 166 167 // Populate libgl_dir with a symlink farm to files matching glob_list. 168 // 169 // The symbolic links are made in one of two ways. If the library found is a 170 // file a regular symlink "$libname" -> "/path/to/hostfs/$libname" is created. 171 // If the library is a symbolic link then relative links are kept as-is but 172 // absolute links are translated to have "/path/to/hostfs" up front so that 173 // they work after the pivot_root elsewhere. 174 // 175 // The glob list passed to us is produced with paths relative to source dir, 176 // to simplify the various tie-in points with this function. 177 static void sc_populate_libgl_with_hostfs_symlinks(const char *libgl_dir, 178 const char *source_dir, 179 const char *glob_list[], 180 size_t glob_list_len) 181 { 182 size_t source_dir_len = strlen(source_dir); 183 glob_t glob_res SC_CLEANUP(globfree) = { 184 .gl_pathv = NULL 185 }; 186 // Find all the entries matching the list of globs 187 for (size_t i = 0; i < glob_list_len; ++i) { 188 const char *glob_pattern = glob_list[i]; 189 char glob_pattern_full[512] = { 0 }; 190 sc_must_snprintf(glob_pattern_full, sizeof glob_pattern_full, 191 "%s/%s", source_dir, glob_pattern); 192 193 int err = glob(glob_pattern_full, i ? GLOB_APPEND : 0, NULL, 194 &glob_res); 195 // Not all of the files have to be there (they differ depending on the 196 // driver version used). Ignore all errors that are not GLOB_NOMATCH. 197 if (err != 0 && err != GLOB_NOMATCH) { 198 die("cannot search using glob pattern %s: %d", 199 glob_pattern_full, err); 200 } 201 } 202 // Symlink each file found 203 for (size_t i = 0; i < glob_res.gl_pathc; ++i) { 204 char symlink_name[512] = { 0 }; 205 char symlink_target[512] = { 0 }; 206 char prefix_dir[512] = { 0 }; 207 const char *pathname = glob_res.gl_pathv[i]; 208 char *pathname_copy1 209 SC_CLEANUP(sc_cleanup_string) = sc_strdup(pathname); 210 char *pathname_copy2 211 SC_CLEANUP(sc_cleanup_string) = sc_strdup(pathname); 212 // POSIX dirname() and basename() may modify their input arguments 213 char *filename = basename(pathname_copy1); 214 char *directory_name = dirname(pathname_copy2); 215 sc_must_snprintf(prefix_dir, sizeof prefix_dir, "%s", 216 libgl_dir); 217 218 if (strlen(directory_name) > source_dir_len) { 219 // Additional path elements between source_dir and dirname, meaning the 220 // actual file is not placed directly under source_dir but under one or 221 // more directories below source_dir. Make sure to recreate the whole 222 // prefix 223 sc_must_snprintf(prefix_dir, sizeof prefix_dir, 224 "%s%s", libgl_dir, 225 &directory_name[source_dir_len]); 226 sc_identity old = 227 sc_set_effective_identity(sc_root_group_identity()); 228 if (sc_nonfatal_mkpath(prefix_dir, 0755) != 0) { 229 die("failed to create prefix path: %s", 230 prefix_dir); 231 } 232 (void)sc_set_effective_identity(old); 233 } 234 235 struct stat stat_buf; 236 int err = lstat(pathname, &stat_buf); 237 if (err != 0) { 238 die("cannot stat file %s", pathname); 239 } 240 switch (stat_buf.st_mode & S_IFMT) { 241 case S_IFLNK:; 242 // Read the target of the symbolic link 243 char hostfs_symlink_target[512] = { 0 }; 244 ssize_t num_read; 245 hostfs_symlink_target[0] = 0; 246 num_read = 247 readlink(pathname, hostfs_symlink_target, 248 sizeof hostfs_symlink_target - 1); 249 if (num_read == -1) { 250 die("cannot read symbolic link %s", pathname); 251 } 252 hostfs_symlink_target[num_read] = 0; 253 if (hostfs_symlink_target[0] == '/') { 254 sc_must_snprintf(symlink_target, 255 sizeof symlink_target, 256 "/var/lib/snapd/hostfs%s", 257 hostfs_symlink_target); 258 } else { 259 // Keep relative symlinks as-is, so that they point to -> libfoo.so.0.123 260 sc_must_snprintf(symlink_target, 261 sizeof symlink_target, "%s", 262 hostfs_symlink_target); 263 } 264 break; 265 case S_IFREG: 266 sc_must_snprintf(symlink_target, 267 sizeof symlink_target, 268 "/var/lib/snapd/hostfs%s", pathname); 269 break; 270 default: 271 debug("ignoring unsupported entry: %s", pathname); 272 continue; 273 } 274 sc_must_snprintf(symlink_name, sizeof symlink_name, 275 "%s/%s", prefix_dir, filename); 276 debug("creating symbolic link %s -> %s", symlink_name, 277 symlink_target); 278 279 // Make sure we don't have some link already (merged GLVND systems) 280 if (lstat(symlink_name, &stat_buf) == 0) { 281 if (unlink(symlink_name) != 0) { 282 die("cannot remove symbolic link target %s", 283 symlink_name); 284 } 285 } 286 287 if (symlink(symlink_target, symlink_name) != 0) { 288 die("cannot create symbolic link %s -> %s", 289 symlink_name, symlink_target); 290 } 291 } 292 } 293 294 static void sc_mkdir_and_mount_and_glob_files(const char *rootfs_dir, 295 const char *source_dir[], 296 size_t source_dir_len, 297 const char *tgt_dir, 298 const char *glob_list[], 299 size_t glob_list_len) 300 { 301 // Bind mount a tmpfs on $rootfs_dir/$tgt_dir (i.e. /var/lib/snapd/lib/gl) 302 char buf[512] = { 0 }; 303 sc_must_snprintf(buf, sizeof(buf), "%s%s", rootfs_dir, tgt_dir); 304 const char *libgl_dir = buf; 305 306 sc_identity old = sc_set_effective_identity(sc_root_group_identity()); 307 int res = mkdir(libgl_dir, 0755); 308 if (res != 0 && errno != EEXIST) { 309 die("cannot create tmpfs target %s", libgl_dir); 310 } 311 if (res == 0 && (chown(libgl_dir, 0, 0) < 0)) { 312 // Adjust the ownership only if we created the directory. 313 die("cannot change ownership of %s", libgl_dir); 314 } 315 (void)sc_set_effective_identity(old); 316 317 debug("mounting tmpfs at %s", libgl_dir); 318 if (mount("none", libgl_dir, "tmpfs", MS_NODEV | MS_NOEXEC, NULL) != 0) { 319 die("cannot mount tmpfs at %s", libgl_dir); 320 }; 321 322 for (size_t i = 0; i < source_dir_len; i++) { 323 // Populate libgl_dir with symlinks to libraries from hostfs 324 sc_populate_libgl_with_hostfs_symlinks(libgl_dir, source_dir[i], 325 glob_list, 326 glob_list_len); 327 } 328 // Remount $tgt_dir (i.e. .../lib/gl) read only 329 debug("remounting tmpfs as read-only %s", libgl_dir); 330 if (mount(NULL, buf, NULL, MS_REMOUNT | MS_BIND | MS_RDONLY, NULL) != 0) { 331 die("cannot remount %s as read-only", buf); 332 } 333 } 334 335 #ifdef NVIDIA_BIARCH 336 337 // Expose host NVIDIA drivers to the snap on biarch systems. 338 // 339 // Order is absolutely imperative here. We'll attempt to find the 340 // primary files for the architecture in the main directory, and end 341 // up copying any files across. However it is possible we're using a 342 // GLVND enabled host, in which case we copied libGL* to the farm. 343 // The next step in the list is to look within the private nvidia 344 // directory, exposed using ld.so.conf tricks within the host OS. 345 // In some distros (i.e. Solus) only the private libGL/libEGL files 346 // may be found here, and they'll clobber the existing GLVND files from 347 // the previous run. 348 // In other distros (like Fedora) all NVIDIA libraries are contained 349 // within the private directory, so we clobber the GLVND files and we 350 // also grab all the private NVIDIA libraries. 351 // 352 // In non GLVND cases we just copy across the exposed libGLs and NVIDIA 353 // libraries from wherever we find, and clobbering is also harmless. 354 static void sc_mount_nvidia_driver_biarch(const char *rootfs_dir) 355 { 356 357 const char *native_sources[] = { 358 NATIVE_LIBDIR, 359 NATIVE_LIBDIR "/nvidia*", 360 }; 361 const size_t native_sources_len = 362 sizeof native_sources / sizeof *native_sources; 363 364 #if UINTPTR_MAX == 0xffffffffffffffff 365 // Alternative 32-bit support 366 const char *lib32_sources[] = { 367 LIB32_DIR, 368 LIB32_DIR "/nvidia*", 369 }; 370 const size_t lib32_sources_len = 371 sizeof lib32_sources / sizeof *lib32_sources; 372 #endif 373 374 // Primary arch 375 sc_mkdir_and_mount_and_glob_files(rootfs_dir, 376 native_sources, native_sources_len, 377 SC_LIBGL_DIR, nvidia_globs, 378 nvidia_globs_len); 379 380 #if UINTPTR_MAX == 0xffffffffffffffff 381 // Alternative 32-bit support 382 sc_mkdir_and_mount_and_glob_files(rootfs_dir, lib32_sources, 383 lib32_sources_len, SC_LIBGL32_DIR, 384 nvidia_globs, nvidia_globs_len); 385 #endif 386 } 387 388 #endif // ifdef NVIDIA_BIARCH 389 390 #ifdef NVIDIA_MULTIARCH 391 392 typedef struct { 393 int major; 394 // Driver version format is MAJOR.MINOR[.MICRO] but we only care about the 395 // major version and the full version string. The micro component has been 396 // seen with relevant leading zeros (e.g. "440.48.02"). 397 char raw[128]; // The size was picked as "big enough" for version strings. 398 } sc_nv_version; 399 400 static void sc_probe_nvidia_driver(sc_nv_version * version) 401 { 402 memset(version, 0, sizeof *version); 403 404 FILE *file SC_CLEANUP(sc_cleanup_file) = NULL; 405 debug("opening file describing nvidia driver version"); 406 file = fopen(SC_NVIDIA_DRIVER_VERSION_FILE, "rt"); 407 if (file == NULL) { 408 if (errno == ENOENT) { 409 debug("nvidia driver version file doesn't exist"); 410 return; 411 } 412 die("cannot open file describing nvidia driver version"); 413 } 414 int nread = fread(version->raw, 1, sizeof version->raw - 1, file); 415 if (nread < 0) { 416 die("cannot read nvidia driver version string"); 417 } 418 if (nread == sizeof version->raw - 1 && !feof(file)) { 419 die("cannot fit entire nvidia driver version string"); 420 } 421 version->raw[nread] = '\0'; 422 if (nread > 0 && version->raw[nread - 1] == '\n') { 423 version->raw[nread - 1] = '\0'; 424 } 425 if (sscanf(version->raw, "%d.", &version->major) != 1) { 426 die("cannot parse major version from nvidia driver version string"); 427 } 428 } 429 430 static void sc_mkdir_and_mount_and_bind(const char *rootfs_dir, 431 const char *src_dir, 432 const char *tgt_dir) 433 { 434 sc_nv_version version; 435 436 // Probe sysfs to get the version of the driver that is currently inserted. 437 sc_probe_nvidia_driver(&version); 438 439 // If there's driver in the kernel then don't mount userspace. 440 if (version.major == 0) { 441 return; 442 } 443 // Construct the paths for the driver userspace libraries 444 // and for the gl directory. 445 char src[PATH_MAX] = { 0 }; 446 char dst[PATH_MAX] = { 0 }; 447 sc_must_snprintf(src, sizeof src, "%s-%d", src_dir, version.major); 448 sc_must_snprintf(dst, sizeof dst, "%s%s", rootfs_dir, tgt_dir); 449 450 // If there is no userspace driver available then don't try to mount it. 451 // This can happen for any number of reasons but one interesting one is 452 // that that snapd runs in a lxd container on a host that uses nvidia. In 453 // that case the container may not have the userspace library installed but 454 // the kernel will still have the module around. 455 if (access(src, F_OK) != 0) { 456 return; 457 } 458 sc_identity old = sc_set_effective_identity(sc_root_group_identity()); 459 int res = mkdir(dst, 0755); 460 if (res != 0 && errno != EEXIST) { 461 die("cannot create directory %s", dst); 462 } 463 if (res == 0 && (chown(dst, 0, 0) < 0)) { 464 // Adjust the ownership only if we created the directory. 465 die("cannot change ownership of %s", dst); 466 } 467 (void)sc_set_effective_identity(old); 468 // Bind mount the binary nvidia driver into $tgt_dir (i.e. /var/lib/snapd/lib/gl). 469 debug("bind mounting nvidia driver %s -> %s", src, dst); 470 if (mount(src, dst, NULL, MS_BIND, NULL) != 0) { 471 die("cannot bind mount nvidia driver %s -> %s", src, dst); 472 } 473 } 474 475 static int sc_mount_nvidia_is_driver_in_dir(const char *dir) 476 { 477 char driver_path[512] = { 0 }; 478 479 sc_nv_version version; 480 481 // Probe sysfs to get the version of the driver that is currently inserted. 482 sc_probe_nvidia_driver(&version); 483 484 // If there's no driver then we should not bother ourselves with finding the 485 // matching library 486 if (version.major == 0) { 487 return 0; 488 } 489 490 // Probe if a well known library is found in directory dir. We must use the 491 // raw version because it may contain more than just major.minor. In 492 // practice the micro version may have leading zeros that are relevant. 493 sc_must_snprintf(driver_path, sizeof driver_path, 494 "%s/libnvidia-glcore.so.%s", dir, version.raw); 495 496 debug("looking for nvidia canary file %s", driver_path); 497 if (access(driver_path, F_OK) == 0) { 498 debug("nvidia library detected at path %s", driver_path); 499 return 1; 500 } 501 return 0; 502 } 503 504 static void sc_mount_nvidia_driver_multiarch(const char *rootfs_dir) 505 { 506 const char *native_libdir = NATIVE_LIBDIR "/" HOST_ARCH_TRIPLET; 507 const char *lib32_libdir = NATIVE_LIBDIR "/" HOST_ARCH32_TRIPLET; 508 509 if ((strlen(HOST_ARCH_TRIPLET) > 0) && 510 (sc_mount_nvidia_is_driver_in_dir(native_libdir) == 1)) { 511 512 // sc_mkdir_and_mount_and_glob_files() takes an array of strings, so 513 // initialize native_sources accordingly, but calculate the array length 514 // dynamically to make adjustments to native_sources easier. 515 const char *native_sources[] = { native_libdir }; 516 const size_t native_sources_len = 517 sizeof native_sources / sizeof *native_sources; 518 // Primary arch 519 sc_mkdir_and_mount_and_glob_files(rootfs_dir, 520 native_sources, 521 native_sources_len, 522 SC_LIBGL_DIR, nvidia_globs, 523 nvidia_globs_len); 524 525 // Alternative 32-bit support 526 if ((strlen(HOST_ARCH32_TRIPLET) > 0) && 527 (sc_mount_nvidia_is_driver_in_dir(lib32_libdir) == 1)) { 528 529 // sc_mkdir_and_mount_and_glob_files() takes an array of strings, so 530 // initialize lib32_sources accordingly, but calculate the array length 531 // dynamically to make adjustments to lib32_sources easier. 532 const char *lib32_sources[] = { lib32_libdir }; 533 const size_t lib32_sources_len = 534 sizeof lib32_sources / sizeof *lib32_sources; 535 sc_mkdir_and_mount_and_glob_files(rootfs_dir, 536 lib32_sources, 537 lib32_sources_len, 538 SC_LIBGL32_DIR, 539 nvidia_globs, 540 nvidia_globs_len); 541 } 542 } else { 543 // Attempt mount of both the native and 32-bit variants of the driver if they exist 544 sc_mkdir_and_mount_and_bind(rootfs_dir, "/usr/lib/nvidia", 545 SC_LIBGL_DIR); 546 // Alternative 32-bit support 547 sc_mkdir_and_mount_and_bind(rootfs_dir, "/usr/lib32/nvidia", 548 SC_LIBGL32_DIR); 549 } 550 } 551 552 #endif // ifdef NVIDIA_MULTIARCH 553 554 static void sc_mount_vulkan(const char *rootfs_dir) 555 { 556 const char *vulkan_sources[] = { 557 SC_VULKAN_SOURCE_DIR, 558 }; 559 const size_t vulkan_sources_len = 560 sizeof vulkan_sources / sizeof *vulkan_sources; 561 562 sc_mkdir_and_mount_and_glob_files(rootfs_dir, vulkan_sources, 563 vulkan_sources_len, SC_VULKAN_DIR, 564 vulkan_globs, vulkan_globs_len); 565 } 566 567 static void sc_mount_egl(const char *rootfs_dir) 568 { 569 const char *egl_vendor_sources[] = { SC_EGL_VENDOR_SOURCE_DIR }; 570 const size_t egl_vendor_sources_len = 571 sizeof egl_vendor_sources / sizeof *egl_vendor_sources; 572 573 sc_mkdir_and_mount_and_glob_files(rootfs_dir, egl_vendor_sources, 574 egl_vendor_sources_len, SC_GLVND_DIR, 575 egl_vendor_globs, 576 egl_vendor_globs_len); 577 } 578 579 void sc_mount_nvidia_driver(const char *rootfs_dir) 580 { 581 /* If NVIDIA module isn't loaded, don't attempt to mount the drivers */ 582 if (access(SC_NVIDIA_DRIVER_VERSION_FILE, F_OK) != 0) { 583 return; 584 } 585 586 sc_identity old = sc_set_effective_identity(sc_root_group_identity()); 587 int res = mkdir(SC_LIB, 0755); 588 if (res != 0 && errno != EEXIST) { 589 die("cannot create " SC_LIB); 590 } 591 if (res == 0 && (chown(SC_LIB, 0, 0) < 0)) { 592 // Adjust the ownership only if we created the directory. 593 die("cannot change ownership of " SC_LIB); 594 } 595 (void)sc_set_effective_identity(old); 596 #ifdef NVIDIA_MULTIARCH 597 sc_mount_nvidia_driver_multiarch(rootfs_dir); 598 #endif // ifdef NVIDIA_MULTIARCH 599 #ifdef NVIDIA_BIARCH 600 sc_mount_nvidia_driver_biarch(rootfs_dir); 601 #endif // ifdef NVIDIA_BIARCH 602 603 // Common for both driver mechanisms 604 sc_mount_vulkan(rootfs_dir); 605 sc_mount_egl(rootfs_dir); 606 }