summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--DRIVER_VERSION2
-rw-r--r--backup.c14
-rw-r--r--install-from-cwd.c4
-rw-r--r--kernel.c4
-rw-r--r--log.c119
-rw-r--r--misc.c218
-rw-r--r--misc.h1
-rw-r--r--nvidia-installer.c1
-rw-r--r--nvidia-installer.h1
-rw-r--r--option_table.h4
10 files changed, 313 insertions, 55 deletions
diff --git a/DRIVER_VERSION b/DRIVER_VERSION
index 5abfad7..b319f2d 100644
--- a/DRIVER_VERSION
+++ b/DRIVER_VERSION
@@ -1 +1 @@
-71.86.14
+71.86.15
diff --git a/backup.c b/backup.c
index c67f1a0..3dd1f02 100644
--- a/backup.c
+++ b/backup.c
@@ -49,6 +49,8 @@
#define BACKUP_DIRECTORY "/var/lib/nvidia"
#define BACKUP_LOG (BACKUP_DIRECTORY "/log")
+#define RMMOD_MODULE_NAME "nvidia"
+
/*
* XXX when uninstalling should we remove directories that were
* created by our installation?
@@ -117,7 +119,6 @@ typedef struct {
} BackupInfo;
-
static BackupInfo *read_backup_log_file(Options *op);
static int check_backup_log_entries(Options *op, BackupInfo *b);
@@ -498,7 +499,7 @@ static int do_uninstall(Options *op)
BackupLogEntry *e;
BackupInfo *b;
int i, len, ok;
- char *tmpstr;
+ char *tmpstr, *cmd;
float percent;
static const char existing_installation_is_borked[] =
@@ -656,6 +657,15 @@ static int do_uninstall(Options *op)
/* XXX what to do if this fails?... nothing */
}
+ /*
+ * attempt to unload the kernel module, but don't abort if this fails: the
+ * kernel may not have been configured with support for module unloading
+ * (Linux 2.6) or the user might have unloaded it themselves.
+ */
+ cmd = nvstrcat(op->utils[RMMOD], " ", RMMOD_MODULE_NAME, NULL);
+ run_command(op, cmd, NULL, FALSE, 0, TRUE);
+ nvfree(cmd);
+
run_distro_hook(op, "post-uninstall");
return TRUE;
diff --git a/install-from-cwd.c b/install-from-cwd.c
index 7a7aac4..88ceae3 100644
--- a/install-from-cwd.c
+++ b/install-from-cwd.c
@@ -130,6 +130,10 @@ int install_from_cwd(Options *op)
}
ran_pre_install_hook = TRUE;
+ /* fail if the nouveau driver is currently in use */
+
+ if (!check_for_nouveau(op)) goto failed;
+
/* attempt to build a kernel module for the target kernel */
if (!op->no_kernel_module) {
diff --git a/kernel.c b/kernel.c
index 3e691d9..75ab55f 100644
--- a/kernel.c
+++ b/kernel.c
@@ -724,8 +724,8 @@ int test_kernel_module(Options *op, Package *p)
"built against the wrong or improperly configured "
"kernel sources, with a version of gcc that differs "
"from the one used to build the target kernel, or "
- "if a driver such as rivafb/nvidiafb is present and "
- "prevents the NVIDIA kernel module from obtaining "
+ "if a driver such as rivafb, nvidiafb, or nouveau is present "
+ "and prevents the NVIDIA kernel module from obtaining "
"ownership of the NVIDIA graphics device(s).\n\n"
"Please see the log entries 'Kernel module load "
"error' and 'Kernel messages' at the end of the file "
diff --git a/log.c b/log.c
index 62641b8..49fa4d3 100644
--- a/log.c
+++ b/log.c
@@ -79,6 +79,7 @@ static FILE *log_file_stream;
void log_init(Options *op)
{
time_t now;
+ char *path;
if (!op->logging) return;
@@ -100,108 +101,126 @@ void log_init(Options *op)
log_printf(op, TRUE, NULL, "installer version: %s",
NVIDIA_INSTALLER_VERSION);
log_printf(op, TRUE, NULL, "");
-
+
+ path = getenv("PATH");
+ log_printf(op, TRUE, NULL, "PATH: %s", STRSTR(path));
+ log_printf(op, TRUE, NULL, "");
+
log_printf(op, TRUE, NULL, "option status:");
- log_printf(op, TRUE, NULL, " license pre-accepted : %s",
+ log_printf(op, TRUE, NULL, " license pre-accepted : %s",
BOOLSTR(op->accept_license));
- log_printf(op, TRUE, NULL, " update : %s",
+ log_printf(op, TRUE, NULL, " update : %s",
BOOLSTR(op->update));
- log_printf(op, TRUE, NULL, " force update : %s",
+ log_printf(op, TRUE, NULL, " force update : %s",
BOOLSTR(op->force_update));
- log_printf(op, TRUE, NULL, " expert : %s",
+ log_printf(op, TRUE, NULL, " expert : %s",
BOOLSTR(op->expert));
- log_printf(op, TRUE, NULL, " uninstall : %s",
+ log_printf(op, TRUE, NULL, " uninstall : %s",
BOOLSTR(op->uninstall));
- log_printf(op, TRUE, NULL, " driver info : %s",
+ log_printf(op, TRUE, NULL, " driver info : %s",
BOOLSTR(op->driver_info));
- log_printf(op, TRUE, NULL, " precompiled interfaces : %s",
+ log_printf(op, TRUE, NULL, " precompiled interfaces : %s",
BOOLSTR(!op->no_precompiled_interface));
- log_printf(op, TRUE, NULL, " no ncurses color : %s",
+ log_printf(op, TRUE, NULL, " no ncurses color : %s",
BOOLSTR(op->no_ncurses_color));
- log_printf(op, TRUE, NULL, " query latest version : %s",
+ log_printf(op, TRUE, NULL, " query latest version : %s",
BOOLSTR(op->latest));
- log_printf(op, TRUE, NULL, " OpenGL header files : %s",
+ log_printf(op, TRUE, NULL, " OpenGL header files : %s",
BOOLSTR(op->opengl_headers));
- log_printf(op, TRUE, NULL, " no questions : %s",
+ log_printf(op, TRUE, NULL, " no questions : %s",
BOOLSTR(op->no_questions));
- log_printf(op, TRUE, NULL, " silent : %s",
+ log_printf(op, TRUE, NULL, " silent : %s",
BOOLSTR(op->silent));
- log_printf(op, TRUE, NULL, " no recursion : %s",
+ log_printf(op, TRUE, NULL, " no recursion : %s",
BOOLSTR(op->no_recursion));
- log_printf(op, TRUE, NULL, " no backup : %s",
+ log_printf(op, TRUE, NULL, " no backup : %s",
BOOLSTR(op->no_backup));
- log_printf(op, TRUE, NULL, " kernel module only : %s",
+ log_printf(op, TRUE, NULL, " kernel module only : %s",
BOOLSTR(op->kernel_module_only));
- log_printf(op, TRUE, NULL, " sanity : %s",
+ log_printf(op, TRUE, NULL, " sanity : %s",
BOOLSTR(op->sanity));
- log_printf(op, TRUE, NULL, " add this kernel : %s",
+ log_printf(op, TRUE, NULL, " add this kernel : %s",
BOOLSTR(op->add_this_kernel));
- log_printf(op, TRUE, NULL, " no runlevel check : %s",
+ log_printf(op, TRUE, NULL, " no runlevel check : %s",
BOOLSTR(op->no_runlevel_check));
- log_printf(op, TRUE, NULL, " no network : %s",
+ log_printf(op, TRUE, NULL, " no network : %s",
BOOLSTR(op->no_network));
- log_printf(op, TRUE, NULL, " no ABI note : %s",
+ log_printf(op, TRUE, NULL, " no ABI note : %s",
BOOLSTR(op->no_abi_note));
- log_printf(op, TRUE, NULL, " no RPMs : %s",
+ log_printf(op, TRUE, NULL, " no RPMs : %s",
BOOLSTR(op->no_rpms));
- log_printf(op, TRUE, NULL, " no kernel module : %s",
+ log_printf(op, TRUE, NULL, " no kernel module : %s",
BOOLSTR(op->no_kernel_module));
- log_printf(op, TRUE, NULL, " force SELinux : %s",
+ log_printf(op, TRUE, NULL, " force SELinux : %s",
SELINUXSTR(op->selinux_option));
- log_printf(op, TRUE, NULL, " no X server check : %s",
+ log_printf(op, TRUE, NULL, " no X server check : %s",
BOOLSTR(op->no_x_check));
- log_printf(op, TRUE, NULL, " no cc version check : %s",
+ log_printf(op, TRUE, NULL, " no cc version check : %s",
BOOLSTR(op->ignore_cc_version_check));
- log_printf(op, TRUE, NULL, " force tls : %s",
+ log_printf(op, TRUE, NULL, " run distro scripts : %s",
+ BOOLSTR(op->run_distro_scripts));
+ log_printf(op, TRUE, NULL, " no nouveau check : %s",
+ BOOLSTR(op->no_nouveau_check));
+ log_printf(op, TRUE, NULL, " sigwinch work around : %s",
+ BOOLSTR(op->sigwinch_workaround));
+ log_printf(op, TRUE, NULL, " force tls : %s",
TLSSTR(op->which_tls));
#if defined(NV_X86_64)
- log_printf(op, TRUE, NULL, " force compat32 tls : %s",
+ log_printf(op, TRUE, NULL, " force compat32 tls : %s",
TLSSTR(op->which_tls_compat32));
#endif
- log_printf(op, TRUE, NULL, " X install prefix : %s",
+ log_printf(op, TRUE, NULL, " X install prefix : %s",
STRSTR(op->x_prefix));
- log_printf(op, TRUE, NULL, " X library install path : %s",
+ log_printf(op, TRUE, NULL, " X library install path : %s",
STRSTR(op->x_library_path));
- log_printf(op, TRUE, NULL, " X module install path : %s",
+ log_printf(op, TRUE, NULL, " X module install path : %s",
STRSTR(op->x_module_path));
- log_printf(op, TRUE, NULL, " OpenGL install prefix : %s",
+ log_printf(op, TRUE, NULL, " OpenGL install prefix : %s",
STRSTR(op->opengl_prefix));
- log_printf(op, TRUE, NULL, " OpenGL install libdir : %s",
+ log_printf(op, TRUE, NULL, " OpenGL install libdir : %s",
STRSTR(op->opengl_libdir));
#if defined(NV_X86_64)
- log_printf(op, TRUE, NULL, " compat32 install chroot : %s",
+ log_printf(op, TRUE, NULL, " compat32 install chroot : %s",
STRSTR(op->compat32_chroot));
- log_printf(op, TRUE, NULL, " compat32 install prefix : %s",
+ log_printf(op, TRUE, NULL, " compat32 install prefix : %s",
STRSTR(op->compat32_prefix));
- log_printf(op, TRUE, NULL, " compat32 install libdir : %s",
+ log_printf(op, TRUE, NULL, " compat32 install libdir : %s",
STRSTR(op->compat32_libdir));
#endif
- log_printf(op, TRUE, NULL, " utility install prefix : %s",
+ log_printf(op, TRUE, NULL, " utility install prefix : %s",
STRSTR(op->utility_prefix));
- log_printf(op, TRUE, NULL, " utility install libdir : %s",
+ log_printf(op, TRUE, NULL, " utility install libdir : %s",
STRSTR(op->utility_libdir));
- log_printf(op, TRUE, NULL, " doc install prefix : %s",
+ log_printf(op, TRUE, NULL, " installer prefix : %s",
+ STRSTR(op->installer_prefix));
+ log_printf(op, TRUE, NULL, " doc install prefix : %s",
STRSTR(op->documentation_prefix));
- log_printf(op, TRUE, NULL, " kernel name : %s",
+ log_printf(op, TRUE, NULL, " kernel name : %s",
STRSTR(op->kernel_name));
- log_printf(op, TRUE, NULL, " kernel include path : %s",
+ log_printf(op, TRUE, NULL, " kernel include path : %s",
STRSTR(op->kernel_include_path));
- log_printf(op, TRUE, NULL, " kernel source path : %s",
+ log_printf(op, TRUE, NULL, " kernel source path : %s",
STRSTR(op->kernel_source_path));
- log_printf(op, TRUE, NULL, " kernel output path : %s",
+ log_printf(op, TRUE, NULL, " kernel output path : %s",
STRSTR(op->kernel_output_path));
- log_printf(op, TRUE, NULL, " kernel install path : %s",
+ log_printf(op, TRUE, NULL, " kernel install path : %s",
STRSTR(op->kernel_module_installation_path));
- log_printf(op, TRUE, NULL, " proc mount point : %s",
+ log_printf(op, TRUE, NULL, " precompiled kernel interfaces path : %s",
+ STRSTR(op->precompiled_kernel_interfaces_path));
+ log_printf(op, TRUE, NULL, " precompiled kernel interfaces url : %s",
+ STRSTR(op->precompiled_kernel_interfaces_url));
+ log_printf(op, TRUE, NULL, " proc mount point : %s",
STRSTR(op->proc_mount_point));
- log_printf(op, TRUE, NULL, " ui : %s",
+ log_printf(op, TRUE, NULL, " ui : %s",
STRSTR(op->ui_str));
- log_printf(op, TRUE, NULL, " tmpdir : %s",
+ log_printf(op, TRUE, NULL, " tmpdir : %s",
STRSTR(op->tmpdir));
- log_printf(op, TRUE, NULL, " ftp mirror : %s",
+ log_printf(op, TRUE, NULL, " ftp mirror : %s",
STRSTR(op->ftp_site));
- log_printf(op, TRUE, NULL, " RPM file list : %s",
+ log_printf(op, TRUE, NULL, " RPM file list : %s",
STRSTR(op->rpm_file_list));
+ log_printf(op, TRUE, NULL, " selinux chcon type : %s",
+ STRSTR(op->selinux_chcon_type));
log_printf(op, TRUE, NULL, "");
@@ -211,7 +230,7 @@ void log_init(Options *op)
/*
- * log_printf() - if the logggin option is set, this function writes
+ * log_printf() - if the logging option is set, this function writes
* the given printf-style input to the log_file_stream; if the logging
* option is not set, then nothing is done here.
*/
diff --git a/misc.c b/misc.c
index fae0ead..c627e7a 100644
--- a/misc.c
+++ b/misc.c
@@ -2416,6 +2416,224 @@ done:
return ret;
}
+
+/*
+ * Determine if the nouveau driver is currently in use. We do the
+ * equivalent of:
+ *
+ * ls -l /sys/bus/pci/devices/ /driver | grep nouveau
+ *
+ * The directory structure under /sys/bus/pci/devices/ should contain
+ * a directory for each PCI device, and for those devices with a
+ * kernel driver there will be a "driver" symlink.
+ *
+ * This appears to be consistent with how libpciaccess works.
+ *
+ * Returns TRUE if nouveau is found; returns FALSE if not.
+ */
+
+#define SYSFS_DEVICES_PATH "/sys/bus/pci/devices"
+
+static int nouveau_is_present(void)
+{
+ DIR *dir;
+ struct dirent * ent;
+ int found = FALSE;
+
+ dir = opendir(SYSFS_DEVICES_PATH);
+
+ if (!dir) {
+ return FALSE;
+ }
+
+ while ((ent = readdir(dir)) != NULL) {
+
+ char driver_path[PATH_MAX];
+ char symlink_target[PATH_MAX];
+ char *name;
+ ssize_t ret;
+
+ if ((strcmp(ent->d_name, ".") == 0) ||
+ (strcmp(ent->d_name, "..") == 0)) {
+ continue;
+ }
+
+ snprintf(driver_path, PATH_MAX,
+ SYSFS_DEVICES_PATH "/%s/driver", ent->d_name);
+
+ driver_path[PATH_MAX - 1] = '\0';
+
+ ret = readlink(driver_path, symlink_target, PATH_MAX);
+ if (ret < 0) {
+ continue;
+ }
+
+ /* readlink(3) does not nul-terminate its returned string */
+
+ ret = NV_MIN(ret, PATH_MAX - 1);
+
+ symlink_target[ret] = '\0';
+
+ name = basename(symlink_target);
+
+ if (strcmp(name, "nouveau") == 0) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ closedir(dir);
+
+ return found;
+}
+
+
+
+/*
+ * Write a modprobe configuration fragment to disable loading of
+ * nouveau:
+ *
+ * if [ -d /etc/modprobe.d ]; then
+ * name=/etc/modprobe.d/nvidia-installer-nouveau-blacklist
+ * echo "# generated by nvidia-installer" > $name
+ * echo "blacklist nouveau" >> $name
+ * echo "options nouveau modeset=0" >> $name
+ * fi
+ *
+ * Returns TRUE if successful; returns FALSE if there was a failure.
+ */
+
+#define ETC_MODPROBE_D "/etc/modprobe.d"
+#define ETC_MODPROBE_D_FILE \
+ ETC_MODPROBE_D "/nvidia-installer-disable-nouveau.conf"
+
+/*
+ * this checksum is the result of compute_crc() for the file contents
+ * written in blacklist_nouveau()
+ */
+
+#define ETC_MODPROBE_D_FILE_CKSUM 3728279991U
+
+static int blacklist_nouveau(void)
+{
+ int ret;
+ struct stat stat_buf;
+ FILE *file;
+
+ ret = stat(ETC_MODPROBE_D, &stat_buf);
+
+ if (ret != 0) {
+ return FALSE;
+ }
+
+ file = fopen(ETC_MODPROBE_D_FILE, "w+");
+
+ if (!file) {
+ return FALSE;
+ }
+
+ fprintf(file, "# generated by nvidia-installer\n");
+ fprintf(file, "blacklist nouveau\n");
+ fprintf(file, "options nouveau modeset=0\n");
+
+ ret = fclose(file);
+
+ if (ret != 0) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+/*
+ * Check if the nouveau blacklist file is already present with the
+ * contents that we expect
+ */
+
+static int nouveau_blacklist_file_is_present(Options *op)
+{
+ if (access(ETC_MODPROBE_D_FILE, R_OK) != 0) {
+ return FALSE;
+ }
+
+ if (compute_crc(op, ETC_MODPROBE_D_FILE) != ETC_MODPROBE_D_FILE_CKSUM) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+/*
+ * Check if the nouveau kernel driver is in use. If it is, provide an
+ * appropriate error message and offer to try to disable nouveau.
+ *
+ * Returns FALSE if the nouveau kernel driver is in use (cause
+ * installation to abort); returns TRUE if the nouveau driver is not
+ * in use.
+ */
+
+int check_for_nouveau(Options *op)
+{
+ int ret;
+
+#define NOUVEAU_POINTER_MESSAGE \
+ "Please consult the NVIDIA driver README and your Linux " \
+ "distribution's documentation for details on how to correctly " \
+ "disable the Nouveau kernel driver."
+
+ if (op->no_nouveau_check) return TRUE;
+
+ if (!nouveau_is_present()) return TRUE;
+
+ ui_error(op, "The Nouveau kernel driver is currently in use "
+ "by your system. This driver is incompatible with the NVIDIA "
+ "driver, and must be disabled before proceeding. "
+ NOUVEAU_POINTER_MESSAGE);
+
+ if (nouveau_blacklist_file_is_present(op)) {
+ ui_warn(op, "The modprobe configuration file to disable Nouveau, "
+ ETC_MODPROBE_D_FILE ", is already present. Please be "
+ "sure you have rebooted your system since that file was "
+ "written. If you have rebooted, then Nouveau may be enabled "
+ "for other reasons, such as being included in the system "
+ "initial ramdisk or in your X configuration file. "
+ NOUVEAU_POINTER_MESSAGE);
+ return FALSE;
+ }
+
+ ret = ui_yes_no(op, FALSE, "For some distributions, Nouveau can be "
+ "disabled by adding a file in the modprobe configuration "
+ "directory. Would you like nvidia-installer to attempt "
+ "to create this modprobe file for you?");
+
+ if (ret) {
+ ret = blacklist_nouveau();
+
+ if (ret) {
+ ui_message(op, "The modprobe configuration file to disable "
+ "Nouveau, " ETC_MODPROBE_D_FILE ", has been written. "
+ "For some distributions, this may be sufficient to "
+ "disable Nouveau; other distributions may require "
+ "modification of the initial ramdisk. Please reboot "
+ "your system and attempt NVIDIA driver installation "
+ "again. Note if you later wish to reenable Nouveau, "
+ "you will need to delete the file "
+ ETC_MODPROBE_D_FILE ".");
+ } else {
+ ui_warn(op, "Unable to alter the nouveau modprobe configuration. "
+ NOUVEAU_POINTER_MESSAGE);
+ }
+ }
+
+ return FALSE;
+}
+
+
+
/*
* nv_format_text_rows() - this function breaks the given string str
* into some number of rows, where each row is not longer than the
diff --git a/misc.h b/misc.h
index 5e7b61d..a656344 100644
--- a/misc.h
+++ b/misc.h
@@ -118,6 +118,7 @@ Distribution get_distribution(Options *op);
int check_for_running_x(Options *op);
int check_for_modular_xorg(Options *op);
int run_distro_hook(Options *op, const char *hook);
+int check_for_nouveau(Options *op);
TextRows *nv_format_text_rows(const char *prefix, const char *buf,
int width, int word_boundary);
diff --git a/nvidia-installer.c b/nvidia-installer.c
index 51ccd51..65037db 100644
--- a/nvidia-installer.c
+++ b/nvidia-installer.c
@@ -270,6 +270,7 @@ static void parse_commandline(int argc, char *argv[], Options *op)
op->silent = op->no_questions = op->accept_license = TRUE;
op->ui_str = "none";
break;
+ case 'z': op->no_nouveau_check = TRUE; break;
case 'k':
op->kernel_name = strval;
diff --git a/nvidia-installer.h b/nvidia-installer.h
index 0f06a47..230fdce 100644
--- a/nvidia-installer.h
+++ b/nvidia-installer.h
@@ -138,6 +138,7 @@ typedef struct __options {
int sigwinch_workaround;
int no_x_check;
int run_distro_scripts;
+ int no_nouveau_check;
char *opengl_prefix;
char *opengl_libdir;
diff --git a/option_table.h b/option_table.h
index 99a21d4..bebc995 100644
--- a/option_table.h
+++ b/option_table.h
@@ -412,6 +412,10 @@ static const NVGetoptOption __options[] = {
"for distributing precompiled kernel interfaces in a local area "
"network." },
+ { "no-nouveau-check", 'z', 0,
+ "Normally, nvidia-installer aborts installation if the nouveau kernel "
+ "driver is in use. Use this option to disable this check." },
+
{ "force-selinux", FORCE_SELINUX_OPTION, NVGETOPT_STRING_ARGUMENT,
"Linux installations using SELinux (Security-Enhanced Linux) "
"require that the security type of all shared libraries be set "