diff options
-rw-r--r-- | DRIVER_VERSION | 2 | ||||
-rw-r--r-- | backup.c | 14 | ||||
-rw-r--r-- | install-from-cwd.c | 4 | ||||
-rw-r--r-- | kernel.c | 4 | ||||
-rw-r--r-- | log.c | 119 | ||||
-rw-r--r-- | misc.c | 218 | ||||
-rw-r--r-- | misc.h | 1 | ||||
-rw-r--r-- | nvidia-installer.c | 1 | ||||
-rw-r--r-- | nvidia-installer.h | 1 | ||||
-rw-r--r-- | option_table.h | 4 |
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 @@ -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) { @@ -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 " @@ -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. */ @@ -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 @@ -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 " |