github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/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  	"libcuda.so*",
   100  	"libcudart.so*",
   101  	"libnvcuvid.so*",
   102  	"libnvidia-cfg.so*",
   103  	"libnvidia-compiler.so*",
   104  	"libnvidia-eglcore.so*",
   105  	"libnvidia-egl-wayland*",
   106  	"libnvidia-encode.so*",
   107  	"libnvidia-fatbinaryloader.so*",
   108  	"libnvidia-fbc.so*",
   109  	"libnvidia-glcore.so*",
   110  	"libnvidia-glsi.so*",
   111  	"libnvidia-glvkspirv.so*",
   112  	"libnvidia-ifr.so*",
   113  	"libnvidia-ml.so*",
   114  	"libnvidia-opencl.so*",
   115  	"libnvidia-opticalflow.so*",
   116  	"libnvidia-ptxjitcompiler.so*",
   117  	"libnvidia-rtcore.so*",
   118  	"libnvidia-tls.so*",
   119  	"libnvoptix.so*",
   120  	"tls/libnvidia-tls.so*",
   121  	"vdpau/libvdpau_nvidia.so*",
   122  };
   123  
   124  static const size_t nvidia_globs_len =
   125      sizeof nvidia_globs / sizeof *nvidia_globs;
   126  
   127  #endif				// defined(NVIDIA_BIARCH) || defined(NVIDIA_MULTIARCH)
   128  
   129  // Populate libgl_dir with a symlink farm to files matching glob_list.
   130  //
   131  // The symbolic links are made in one of two ways. If the library found is a
   132  // file a regular symlink "$libname" -> "/path/to/hostfs/$libname" is created.
   133  // If the library is a symbolic link then relative links are kept as-is but
   134  // absolute links are translated to have "/path/to/hostfs" up front so that
   135  // they work after the pivot_root elsewhere.
   136  //
   137  // The glob list passed to us is produced with paths relative to source dir,
   138  // to simplify the various tie-in points with this function.
   139  static void sc_populate_libgl_with_hostfs_symlinks(const char *libgl_dir,
   140  						   const char *source_dir,
   141  						   const char *glob_list[],
   142  						   size_t glob_list_len)
   143  {
   144  	size_t source_dir_len = strlen(source_dir);
   145  	glob_t glob_res SC_CLEANUP(globfree) = {
   146  		.gl_pathv = NULL
   147  	};
   148  	// Find all the entries matching the list of globs
   149  	for (size_t i = 0; i < glob_list_len; ++i) {
   150  		const char *glob_pattern = glob_list[i];
   151  		char glob_pattern_full[512] = { 0 };
   152  		sc_must_snprintf(glob_pattern_full, sizeof glob_pattern_full,
   153  				 "%s/%s", source_dir, glob_pattern);
   154  
   155  		int err = glob(glob_pattern_full, i ? GLOB_APPEND : 0, NULL,
   156  			       &glob_res);
   157  		// Not all of the files have to be there (they differ depending on the
   158  		// driver version used). Ignore all errors that are not GLOB_NOMATCH.
   159  		if (err != 0 && err != GLOB_NOMATCH) {
   160  			die("cannot search using glob pattern %s: %d",
   161  			    glob_pattern_full, err);
   162  		}
   163  	}
   164  	// Symlink each file found
   165  	for (size_t i = 0; i < glob_res.gl_pathc; ++i) {
   166  		char symlink_name[512] = { 0 };
   167  		char symlink_target[512] = { 0 };
   168  		char prefix_dir[512] = { 0 };
   169  		const char *pathname = glob_res.gl_pathv[i];
   170  		char *pathname_copy1
   171  		    SC_CLEANUP(sc_cleanup_string) = sc_strdup(pathname);
   172  		char *pathname_copy2
   173  		    SC_CLEANUP(sc_cleanup_string) = sc_strdup(pathname);
   174  		// POSIX dirname() and basename() may modify their input arguments
   175  		char *filename = basename(pathname_copy1);
   176  		char *directory_name = dirname(pathname_copy2);
   177  		sc_must_snprintf(prefix_dir, sizeof prefix_dir, "%s",
   178  				 libgl_dir);
   179  
   180  		if (strlen(directory_name) > source_dir_len) {
   181  			// Additional path elements between source_dir and dirname, meaning the
   182  			// actual file is not placed directly under source_dir but under one or
   183  			// more directories below source_dir. Make sure to recreate the whole
   184  			// prefix
   185  			sc_must_snprintf(prefix_dir, sizeof prefix_dir,
   186  					 "%s%s", libgl_dir,
   187  					 &directory_name[source_dir_len]);
   188  			sc_identity old =
   189  			    sc_set_effective_identity(sc_root_group_identity());
   190  			if (sc_nonfatal_mkpath(prefix_dir, 0755) != 0) {
   191  				die("failed to create prefix path: %s",
   192  				    prefix_dir);
   193  			}
   194  			(void)sc_set_effective_identity(old);
   195  		}
   196  
   197  		struct stat stat_buf;
   198  		int err = lstat(pathname, &stat_buf);
   199  		if (err != 0) {
   200  			die("cannot stat file %s", pathname);
   201  		}
   202  		switch (stat_buf.st_mode & S_IFMT) {
   203  		case S_IFLNK:;
   204  			// Read the target of the symbolic link
   205  			char hostfs_symlink_target[512] = { 0 };
   206  			ssize_t num_read;
   207  			hostfs_symlink_target[0] = 0;
   208  			num_read =
   209  			    readlink(pathname, hostfs_symlink_target,
   210  				     sizeof hostfs_symlink_target - 1);
   211  			if (num_read == -1) {
   212  				die("cannot read symbolic link %s", pathname);
   213  			}
   214  			hostfs_symlink_target[num_read] = 0;
   215  			if (hostfs_symlink_target[0] == '/') {
   216  				sc_must_snprintf(symlink_target,
   217  						 sizeof symlink_target,
   218  						 "/var/lib/snapd/hostfs%s",
   219  						 hostfs_symlink_target);
   220  			} else {
   221  				// Keep relative symlinks as-is, so that they point to -> libfoo.so.0.123
   222  				sc_must_snprintf(symlink_target,
   223  						 sizeof symlink_target, "%s",
   224  						 hostfs_symlink_target);
   225  			}
   226  			break;
   227  		case S_IFREG:
   228  			sc_must_snprintf(symlink_target,
   229  					 sizeof symlink_target,
   230  					 "/var/lib/snapd/hostfs%s", pathname);
   231  			break;
   232  		default:
   233  			debug("ignoring unsupported entry: %s", pathname);
   234  			continue;
   235  		}
   236  		sc_must_snprintf(symlink_name, sizeof symlink_name,
   237  				 "%s/%s", prefix_dir, filename);
   238  		debug("creating symbolic link %s -> %s", symlink_name,
   239  		      symlink_target);
   240  
   241  		// Make sure we don't have some link already (merged GLVND systems)
   242  		if (lstat(symlink_name, &stat_buf) == 0) {
   243  			if (unlink(symlink_name) != 0) {
   244  				die("cannot remove symbolic link target %s",
   245  				    symlink_name);
   246  			}
   247  		}
   248  
   249  		if (symlink(symlink_target, symlink_name) != 0) {
   250  			die("cannot create symbolic link %s -> %s",
   251  			    symlink_name, symlink_target);
   252  		}
   253  	}
   254  }
   255  
   256  static void sc_mkdir_and_mount_and_glob_files(const char *rootfs_dir,
   257  					      const char *source_dir[],
   258  					      size_t source_dir_len,
   259  					      const char *tgt_dir,
   260  					      const char *glob_list[],
   261  					      size_t glob_list_len)
   262  {
   263  	// Bind mount a tmpfs on $rootfs_dir/$tgt_dir (i.e. /var/lib/snapd/lib/gl)
   264  	char buf[512] = { 0 };
   265  	sc_must_snprintf(buf, sizeof(buf), "%s%s", rootfs_dir, tgt_dir);
   266  	const char *libgl_dir = buf;
   267  
   268  	sc_identity old = sc_set_effective_identity(sc_root_group_identity());
   269  	int res = mkdir(libgl_dir, 0755);
   270  	if (res != 0 && errno != EEXIST) {
   271  		die("cannot create tmpfs target %s", libgl_dir);
   272  	}
   273  	if (res == 0 && (chown(libgl_dir, 0, 0) < 0)) {
   274  		// Adjust the ownership only if we created the directory.
   275  		die("cannot change ownership of %s", libgl_dir);
   276  	}
   277  	(void)sc_set_effective_identity(old);
   278  
   279  	debug("mounting tmpfs at %s", libgl_dir);
   280  	if (mount("none", libgl_dir, "tmpfs", MS_NODEV | MS_NOEXEC, NULL) != 0) {
   281  		die("cannot mount tmpfs at %s", libgl_dir);
   282  	};
   283  
   284  	for (size_t i = 0; i < source_dir_len; i++) {
   285  		// Populate libgl_dir with symlinks to libraries from hostfs
   286  		sc_populate_libgl_with_hostfs_symlinks(libgl_dir, source_dir[i],
   287  						       glob_list,
   288  						       glob_list_len);
   289  	}
   290  	// Remount $tgt_dir (i.e. .../lib/gl) read only
   291  	debug("remounting tmpfs as read-only %s", libgl_dir);
   292  	if (mount(NULL, buf, NULL, MS_REMOUNT | MS_BIND | MS_RDONLY, NULL) != 0) {
   293  		die("cannot remount %s as read-only", buf);
   294  	}
   295  }
   296  
   297  #ifdef NVIDIA_BIARCH
   298  
   299  // Expose host NVIDIA drivers to the snap on biarch systems.
   300  //
   301  // Order is absolutely imperative here. We'll attempt to find the
   302  // primary files for the architecture in the main directory, and end
   303  // up copying any files across. However it is possible we're using a
   304  // GLVND enabled host, in which case we copied libGL* to the farm.
   305  // The next step in the list is to look within the private nvidia
   306  // directory, exposed using ld.so.conf tricks within the host OS.
   307  // In some distros (i.e. Solus) only the private libGL/libEGL files
   308  // may be found here, and they'll clobber the existing GLVND files from
   309  // the previous run.
   310  // In other distros (like Fedora) all NVIDIA libraries are contained
   311  // within the private directory, so we clobber the GLVND files and we
   312  // also grab all the private NVIDIA libraries.
   313  //
   314  // In non GLVND cases we just copy across the exposed libGLs and NVIDIA
   315  // libraries from wherever we find, and clobbering is also harmless.
   316  static void sc_mount_nvidia_driver_biarch(const char *rootfs_dir)
   317  {
   318  
   319  	const char *native_sources[] = {
   320  		NATIVE_LIBDIR,
   321  		NATIVE_LIBDIR "/nvidia*",
   322  	};
   323  	const size_t native_sources_len =
   324  	    sizeof native_sources / sizeof *native_sources;
   325  
   326  #if UINTPTR_MAX == 0xffffffffffffffff
   327  	// Alternative 32-bit support
   328  	const char *lib32_sources[] = {
   329  		LIB32_DIR,
   330  		LIB32_DIR "/nvidia*",
   331  	};
   332  	const size_t lib32_sources_len =
   333  	    sizeof lib32_sources / sizeof *lib32_sources;
   334  #endif
   335  
   336  	// Primary arch
   337  	sc_mkdir_and_mount_and_glob_files(rootfs_dir,
   338  					  native_sources, native_sources_len,
   339  					  SC_LIBGL_DIR, nvidia_globs,
   340  					  nvidia_globs_len);
   341  
   342  #if UINTPTR_MAX == 0xffffffffffffffff
   343  	// Alternative 32-bit support
   344  	sc_mkdir_and_mount_and_glob_files(rootfs_dir, lib32_sources,
   345  					  lib32_sources_len, SC_LIBGL32_DIR,
   346  					  nvidia_globs, nvidia_globs_len);
   347  #endif
   348  }
   349  
   350  #endif				// ifdef NVIDIA_BIARCH
   351  
   352  #ifdef NVIDIA_MULTIARCH
   353  
   354  typedef struct {
   355  	int major;
   356  	// Driver version format is MAJOR.MINOR[.MICRO] but we only care about the
   357  	// major version and the full version string. The micro component has been
   358  	// seen with relevant leading zeros (e.g. "440.48.02").
   359  	char raw[128]; // The size was picked as "big enough" for version strings.
   360  } sc_nv_version;
   361  
   362  static void sc_probe_nvidia_driver(sc_nv_version * version)
   363  {
   364  	memset(version, 0, sizeof *version);
   365  
   366  	FILE *file SC_CLEANUP(sc_cleanup_file) = NULL;
   367  	debug("opening file describing nvidia driver version");
   368  	file = fopen(SC_NVIDIA_DRIVER_VERSION_FILE, "rt");
   369  	if (file == NULL) {
   370  		if (errno == ENOENT) {
   371  			debug("nvidia driver version file doesn't exist");
   372  			return;
   373  		}
   374  		die("cannot open file describing nvidia driver version");
   375  	}
   376  	int nread = fread(version->raw, 1, sizeof version->raw - 1, file);
   377  	if (nread < 0) {
   378  		die("cannot read nvidia driver version string");
   379  	}
   380  	if (nread == sizeof version->raw - 1 && !feof(file)) {
   381  		die("cannot fit entire nvidia driver version string");
   382  	}
   383  	version->raw[nread] = '\0';
   384  	if (nread > 0 && version->raw[nread - 1] == '\n') {
   385  		version->raw[nread - 1] = '\0';
   386  	}
   387  	if (sscanf(version->raw, "%d.", &version->major) != 1) {
   388  		die("cannot parse major version from nvidia driver version string");
   389  	}
   390  }
   391  
   392  static void sc_mkdir_and_mount_and_bind(const char *rootfs_dir,
   393  					const char *src_dir,
   394  					const char *tgt_dir)
   395  {
   396  	sc_nv_version version;
   397  
   398  	// Probe sysfs to get the version of the driver that is currently inserted.
   399  	sc_probe_nvidia_driver(&version);
   400  
   401  	// If there's driver in the kernel then don't mount userspace.
   402  	if (version.major == 0) {
   403  		return;
   404  	}
   405  	// Construct the paths for the driver userspace libraries
   406  	// and for the gl directory.
   407  	char src[PATH_MAX] = { 0 };
   408  	char dst[PATH_MAX] = { 0 };
   409  	sc_must_snprintf(src, sizeof src, "%s-%d", src_dir, version.major);
   410  	sc_must_snprintf(dst, sizeof dst, "%s%s", rootfs_dir, tgt_dir);
   411  
   412  	// If there is no userspace driver available then don't try to mount it.
   413  	// This can happen for any number of reasons but one interesting one is
   414  	// that that snapd runs in a lxd container on a host that uses nvidia. In
   415  	// that case the container may not have the userspace library installed but
   416  	// the kernel will still have the module around.
   417  	if (access(src, F_OK) != 0) {
   418  		return;
   419  	}
   420  	sc_identity old = sc_set_effective_identity(sc_root_group_identity());
   421  	int res = mkdir(dst, 0755);
   422  	if (res != 0 && errno != EEXIST) {
   423  		die("cannot create directory %s", dst);
   424  	}
   425  	if (res == 0 && (chown(dst, 0, 0) < 0)) {
   426  		// Adjust the ownership only if we created the directory.
   427  		die("cannot change ownership of %s", dst);
   428  	}
   429  	(void)sc_set_effective_identity(old);
   430  	// Bind mount the binary nvidia driver into $tgt_dir (i.e. /var/lib/snapd/lib/gl).
   431  	debug("bind mounting nvidia driver %s -> %s", src, dst);
   432  	if (mount(src, dst, NULL, MS_BIND, NULL) != 0) {
   433  		die("cannot bind mount nvidia driver %s -> %s", src, dst);
   434  	}
   435  }
   436  
   437  static int sc_mount_nvidia_is_driver_in_dir(const char *dir)
   438  {
   439  	char driver_path[512] = { 0 };
   440  
   441  	sc_nv_version version;
   442  
   443  	// Probe sysfs to get the version of the driver that is currently inserted.
   444  	sc_probe_nvidia_driver(&version);
   445  
   446  	// If there's no driver then we should not bother ourselves with finding the
   447  	// matching library
   448  	if (version.major == 0) {
   449  		return 0;
   450  	}
   451  
   452  	// Probe if a well known library is found in directory dir. We must use the
   453  	// raw version because it may contain more than just major.minor. In
   454  	// practice the micro version may have leading zeros that are relevant.
   455  	sc_must_snprintf(driver_path, sizeof driver_path,
   456  			 "%s/libnvidia-glcore.so.%s", dir, version.raw);
   457  
   458  	debug("looking for nvidia canary file %s", driver_path);
   459  	if (access(driver_path, F_OK) == 0) {
   460  		debug("nvidia library detected at path %s", driver_path);
   461  		return 1;
   462  	}
   463  	return 0;
   464  }
   465  
   466  static void sc_mount_nvidia_driver_multiarch(const char *rootfs_dir)
   467  {
   468  	const char *native_libdir = NATIVE_LIBDIR "/" HOST_ARCH_TRIPLET;
   469  	const char *lib32_libdir = NATIVE_LIBDIR "/" HOST_ARCH32_TRIPLET;
   470  
   471  	if ((strlen(HOST_ARCH_TRIPLET) > 0) &&
   472  	    (sc_mount_nvidia_is_driver_in_dir(native_libdir) == 1)) {
   473  
   474  		// sc_mkdir_and_mount_and_glob_files() takes an array of strings, so
   475  		// initialize native_sources accordingly, but calculate the array length
   476  		// dynamically to make adjustments to native_sources easier.
   477  		const char *native_sources[] = { native_libdir };
   478  		const size_t native_sources_len =
   479  		    sizeof native_sources / sizeof *native_sources;
   480  		// Primary arch
   481  		sc_mkdir_and_mount_and_glob_files(rootfs_dir,
   482  						  native_sources,
   483  						  native_sources_len,
   484  						  SC_LIBGL_DIR, nvidia_globs,
   485  						  nvidia_globs_len);
   486  
   487  		// Alternative 32-bit support
   488  		if ((strlen(HOST_ARCH32_TRIPLET) > 0) &&
   489  		    (sc_mount_nvidia_is_driver_in_dir(lib32_libdir) == 1)) {
   490  
   491  			// sc_mkdir_and_mount_and_glob_files() takes an array of strings, so
   492  			// initialize lib32_sources accordingly, but calculate the array length
   493  			// dynamically to make adjustments to lib32_sources easier.
   494  			const char *lib32_sources[] = { lib32_libdir };
   495  			const size_t lib32_sources_len =
   496  			    sizeof lib32_sources / sizeof *lib32_sources;
   497  			sc_mkdir_and_mount_and_glob_files(rootfs_dir,
   498  							  lib32_sources,
   499  							  lib32_sources_len,
   500  							  SC_LIBGL32_DIR,
   501  							  nvidia_globs,
   502  							  nvidia_globs_len);
   503  		}
   504  	} else {
   505  		// Attempt mount of both the native and 32-bit variants of the driver if they exist
   506  		sc_mkdir_and_mount_and_bind(rootfs_dir, "/usr/lib/nvidia",
   507  					    SC_LIBGL_DIR);
   508  		// Alternative 32-bit support
   509  		sc_mkdir_and_mount_and_bind(rootfs_dir, "/usr/lib32/nvidia",
   510  					    SC_LIBGL32_DIR);
   511  	}
   512  }
   513  
   514  #endif				// ifdef NVIDIA_MULTIARCH
   515  
   516  static void sc_mount_vulkan(const char *rootfs_dir)
   517  {
   518  	const char *vulkan_sources[] = {
   519  		SC_VULKAN_SOURCE_DIR,
   520  	};
   521  	const size_t vulkan_sources_len =
   522  	    sizeof vulkan_sources / sizeof *vulkan_sources;
   523  
   524  	sc_mkdir_and_mount_and_glob_files(rootfs_dir, vulkan_sources,
   525  					  vulkan_sources_len, SC_VULKAN_DIR,
   526  					  vulkan_globs, vulkan_globs_len);
   527  }
   528  
   529  static void sc_mount_egl(const char *rootfs_dir)
   530  {
   531  	const char *egl_vendor_sources[] = { SC_EGL_VENDOR_SOURCE_DIR };
   532  	const size_t egl_vendor_sources_len =
   533  	    sizeof egl_vendor_sources / sizeof *egl_vendor_sources;
   534  
   535  	sc_mkdir_and_mount_and_glob_files(rootfs_dir, egl_vendor_sources,
   536  					  egl_vendor_sources_len, SC_GLVND_DIR,
   537  					  egl_vendor_globs,
   538  					  egl_vendor_globs_len);
   539  }
   540  
   541  void sc_mount_nvidia_driver(const char *rootfs_dir)
   542  {
   543  	/* If NVIDIA module isn't loaded, don't attempt to mount the drivers */
   544  	if (access(SC_NVIDIA_DRIVER_VERSION_FILE, F_OK) != 0) {
   545  		return;
   546  	}
   547  
   548  	sc_identity old = sc_set_effective_identity(sc_root_group_identity());
   549  	int res = mkdir(SC_LIB, 0755);
   550  	if (res != 0 && errno != EEXIST) {
   551  		die("cannot create " SC_LIB);
   552  	}
   553  	if (res == 0 && (chown(SC_LIB, 0, 0) < 0)) {
   554  		// Adjust the ownership only if we created the directory.
   555  		die("cannot change ownership of " SC_LIB);
   556  	}
   557  	(void)sc_set_effective_identity(old);
   558  #ifdef NVIDIA_MULTIARCH
   559  	sc_mount_nvidia_driver_multiarch(rootfs_dir);
   560  #endif				// ifdef NVIDIA_MULTIARCH
   561  #ifdef NVIDIA_BIARCH
   562  	sc_mount_nvidia_driver_biarch(rootfs_dir);
   563  #endif				// ifdef NVIDIA_BIARCH
   564  
   565  	// Common for both driver mechanisms
   566  	sc_mount_vulkan(rootfs_dir);
   567  	sc_mount_egl(rootfs_dir);
   568  }