summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile51
-rw-r--r--backup.c119
-rw-r--r--backup.h2
-rw-r--r--command-list.c65
-rw-r--r--common-utils/common-utils.c60
-rw-r--r--common-utils/common-utils.h2
-rw-r--r--common-utils/nvgetopt.c3
-rw-r--r--files.c94
-rw-r--r--install-from-cwd.c36
-rw-r--r--misc.c189
-rw-r--r--misc.h4
-rw-r--r--nvidia-installer.c15
-rw-r--r--nvidia-installer.h13
-rw-r--r--option_table.h31
-rw-r--r--utils.mk37
-rw-r--r--version.mk2
16 files changed, 597 insertions, 126 deletions
diff --git a/Makefile b/Makefile
index 087b60e..523f132 100644
--- a/Makefile
+++ b/Makefile
@@ -47,6 +47,7 @@ PCI_LDFLAGS ?=
NVIDIA_INSTALLER = $(OUTPUTDIR)/nvidia-installer
MKPRECOMPILED = $(OUTPUTDIR)/mkprecompiled
MAKESELF_HELP_SCRIPT = $(OUTPUTDIR)/makeself-help-script
+MAKESELF_HELP_SCRIPT_SH = $(OUTPUTDIR)/makeself-help-script.sh
NVIDIA_INSTALLER_PROGRAM_NAME = "nvidia-installer"
@@ -118,10 +119,15 @@ INSTALLER_SRC = $(SRC) $(NCURSES_UI_SO_C) $(TLS_TEST_C) $(TLS_TEST_DSO_C) \
INSTALLER_OBJS = $(call BUILD_OBJECT_LIST,$(INSTALLER_SRC))
-CFLAGS += -I. -imacros $(CONFIG_H) -I $(OUTPUTDIR)
-CFLAGS += -I $(COMMON_UTILS_DIR)
+common_cflags = -I.
+common_cflags += -imacros $(CONFIG_H)
+common_cflags += -I $(OUTPUTDIR)
+common_cflags += -I $(COMMON_UTILS_DIR)
+
+CFLAGS += $(common_cflags)
+
+HOST_CFLAGS += $(common_cflags)
-HOST_CFLAGS += -I. -imacros $(CONFIG_H) -I $(OUTPUTDIR)
LDFLAGS += -L.
LIBS += -ldl
@@ -151,7 +157,8 @@ quiet_GEN_UI_ARRAY = GEN-UI-ARRAY $@
.PNONY: all install NVIDIA_INSTALLER_install MKPRECOMPILED_install \
MANPAGE_install MAKESELF_HELP_SCRIPT_install clean clobber
-all: $(NVIDIA_INSTALLER) $(MKPRECOMPILED) $(MAKESELF_HELP_SCRIPT) $(MANPAGE)
+all: $(NVIDIA_INSTALLER) $(MKPRECOMPILED) $(MAKESELF_HELP_SCRIPT) \
+ $(MAKESELF_HELP_SCRIPT_SH) $(MANPAGE)
install: NVIDIA_INSTALLER_install MKPRECOMPILED_install MANPAGE_install \
MAKESELF_HELP_SCRIPT_install
@@ -226,11 +233,11 @@ $(call BUILD_OBJECT_LIST,misc.c): CFLAGS += $(PCI_CFLAGS)
$(call BUILD_OBJECT_LIST,ncurses-ui.c): CFLAGS += $(NCURSES_CFLAGS) -fPIC
# define the rule to build each object file
-$(foreach src,$(ALL_SRC),$(eval $(call DEFINE_OBJECT_RULE,CC,$(src))))
+$(foreach src,$(ALL_SRC),$(eval $(call DEFINE_OBJECT_RULE,TARGET,$(src))))
# define a rule to build each makeself-help-script object file
$(foreach src,$(MAKESELF_HELP_SCRIPT_SRC),\
- $(eval $(call DEFINE_OBJECT_RULE_WITH_OBJECT_NAME,HOST_CC,$(src),\
+ $(eval $(call DEFINE_OBJECT_RULE_WITH_OBJECT_NAME,HOST,$(src),\
$(call BUILD_MAKESELF_OBJECT_LIST,$(src)))))
# define the rule to generate $(STAMP_C)
@@ -290,6 +297,36 @@ rtld_test: rtld_test.c
##############################################################################
+# rule to build MAKESELF_HELP_SCRIPT_SH; this shell script is packaged
+# with the driver so that the script can be run on any platform when
+# the driver is later repackaged
+##############################################################################
+
+$(MAKESELF_HELP_SCRIPT_SH): $(MAKESELF_HELP_SCRIPT)
+ @ $(ECHO) "#!/bin/sh" > $@
+ @ $(ECHO) "while [ \"\$$1\" ]; do" >> $@
+ @ $(ECHO) " case \$$1 in" >> $@
+ @ $(ECHO) " \"--advanced-options-args-only\")" >> $@
+ @ $(ECHO) " cat <<- \"ADVANCED_OPTIONS_ARGS_ONLY\"" >> $@
+ $(MAKESELF_HELP_SCRIPT) --advanced-options-args-only >> $@
+ @ $(ECHO) "ADVANCED_OPTIONS_ARGS_ONLY" >> $@
+ @ $(ECHO) " ;;" >> $@
+ @ $(ECHO) " \"--help-args-only\")" >> $@
+ @ $(ECHO) " cat <<- \"HELP_ARGS_ONLY\"" >> $@
+ $(MAKESELF_HELP_SCRIPT) --help-args-only >> $@
+ @ $(ECHO) "HELP_ARGS_ONLY" >> $@
+ @ $(ECHO) " ;;" >> $@
+ @ $(ECHO) " *)" >> $@
+ @ $(ECHO) " echo \"unrecognized option '$$1'"\" >> $@
+ @ $(ECHO) " break" >> $@
+ @ $(ECHO) " ;;" >> $@
+ @ $(ECHO) " esac" >> $@
+ @ $(ECHO) " shift" >> $@
+ @ $(ECHO) "done" >> $@
+ $(CHMOD) u+x $@
+
+
+##############################################################################
# Documentation
##############################################################################
@@ -303,7 +340,7 @@ GEN_MANPAGE_OPTS_SRC += $(COMMON_UTILS_DIR)/gen-manpage-opts-helper.c
GEN_MANPAGE_OPTS_OBJS = $(call BUILD_OBJECT_LIST,$(GEN_MANPAGE_OPTS_SRC))
$(foreach src, $(GEN_MANPAGE_OPTS_SRC), \
- $(eval $(call DEFINE_OBJECT_RULE,HOST_CC,$(src))))
+ $(eval $(call DEFINE_OBJECT_RULE,HOST,$(src))))
$(GEN_MANPAGE_OPTS_OBJS): $(CONFIG_H)
diff --git a/backup.c b/backup.c
index 61a44b8..d3125b1 100644
--- a/backup.c
+++ b/backup.c
@@ -43,15 +43,10 @@
#define BACKUP_DIRECTORY "/var/lib/nvidia"
#define BACKUP_LOG (BACKUP_DIRECTORY "/log")
+#define BACKUP_MKDIR_LOG (BACKUP_DIRECTORY "/dirs")
#define RMMOD_MODULE_NAME "nvidia"
-/*
- * XXX when uninstalling should we remove directories that were
- * created by our installation?
- */
-
-
@@ -120,7 +115,7 @@ static void free_backup_info(BackupInfo *b);
static int check_backup_log_entries(Options *op, BackupInfo *b);
-static int do_uninstall(Options *op);
+static int do_uninstall(Options *op, const char *version);
static int sanity_check_backup_log_entries(Options *op, BackupInfo *b);
@@ -487,11 +482,103 @@ static int parse_crc(const char *buf, uint32 *crc)
/*
+ * Syntax for the mkdir log file:
+ *
+ * Each line in the file contains the name of a directory that was created
+ * during driver installation.
+ *
+ * XXX pathnames containing '\n' will break both this file, and the regular
+ * backup log file.
+ */
+
+
+/*
+ * log_mkdir() - takes a newline-delimited list of directories and appends
+ * them to the log of directories created during installation. The caller
+ * should ensure that directories are listed in decreasing order of depth,
+ * so that removing them in that order will work.
+ */
+int log_mkdir(Options *op, const char *dirs)
+{
+ FILE *log;
+
+ /* open the log file */
+
+ log = fopen(BACKUP_MKDIR_LOG, "a");
+ if (!log) {
+ ui_error(op, "Unable to open mkdir log file '%s' (%s).",
+ BACKUP_MKDIR_LOG, strerror(errno));
+ return FALSE;
+ }
+
+ fprintf(log, "%s", dirs);
+
+ /* close the log file */
+
+ if (fclose(log) != 0) {
+ ui_error(op, "Error while closing mkdir log file '%s' (%s).",
+ BACKUP_MKDIR_LOG, strerror(errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * rmdir_recursive() - Use BACKUP_MKDIR_LOG to find directories that were
+ * created by a previous nvidia-installer, and delete any such directories.
+ * Returns TRUE if the log is found and all directories are successfully
+ * deleted; returns FALSE if any directories failed to be deleted or the
+ * log isn't found.
+ */
+static int rmdir_recursive(Options *op)
+{
+ FILE *log;
+ char *dir;
+ int eof = FALSE, ret = TRUE;
+
+ /* open the log file */
+
+ log = fopen(BACKUP_MKDIR_LOG, "r");
+ if (!log) {
+ /* Fail silently: most likely, the current driver was simply installed
+ * with an nvidia-installer that didn't log created directories. */
+ return FALSE;
+ }
+
+ while (!eof) {
+ dir = fget_next_line(log, &eof);
+ if (dir) {
+ /* Ignore empty lines and the backup directory itself, since it is
+ * never empty as long as the dirs file is still around. */
+ if (strlen(dir) && strcmp(dir, BACKUP_DIRECTORY) != 0) {
+ if (rmdir(dir) != 0) {
+ ui_warn(op, "Failed to delete the directory '%s' (%s).",
+ dir, strerror(errno));
+ ret = FALSE;
+ }
+ }
+ }
+ free(dir);
+ }
+
+ /* close the log file */
+
+ if (fclose(log) != 0) {
+ ui_error(op, "Error while closing mkdir log file '%s' (%s).",
+ BACKUP_MKDIR_LOG, strerror(errno));
+ return FALSE;
+ }
+
+ return ret;
+}
+
+/*
* do_uninstall() - this function uninstalls a previously installed
* driver, by parsing the BACKUP_LOG file.
*/
-static int do_uninstall(Options *op)
+static int do_uninstall(Options *op, const char *version)
{
BackupLogEntry *e;
BackupInfo *b;
@@ -537,6 +624,15 @@ static int do_uninstall(Options *op)
free(tmpstr);
+ /* Remove any installed DKMS modules */
+
+ if (dkms_module_installed(op, version)) {
+ ui_log(op, "DKMS module detected; removing...");
+ if (!dkms_remove_module(op, version)) {
+ ui_warn(op, "Failed to remove installed DKMS module!");
+ }
+ }
+
/*
* given the list of Backup logfile entries, perform the necessary
* operations:
@@ -646,6 +742,11 @@ static int do_uninstall(Options *op)
}
}
+ if (!rmdir_recursive(op)) {
+ ui_log(op, "Unable to delete directories created by previous "
+ "installation.");
+ }
+
ui_status_end(op, "done.");
/* remove the backup directory */
@@ -1209,7 +1310,7 @@ int uninstall_existing_driver(Options *op, const int interactive)
}
}
- ret = do_uninstall(op);
+ ret = do_uninstall(op, version);
if (ret) {
if (interactive) {
diff --git a/backup.h b/backup.h
index a0c1fe9..6d1be66 100644
--- a/backup.h
+++ b/backup.h
@@ -39,4 +39,6 @@ int get_installed_driver_version_and_descr(Options *, char **, char **);
int test_installed_files(Options *op);
int find_installed_file(Options *op, char *filename);
+int log_mkdir(Options *op, const char *dirs);
+
#endif /* __NVIDIA_INSTALLER_BACKUP_H__ */
diff --git a/command-list.c b/command-list.c
index 0ccd511..f47bd3f 100644
--- a/command-list.c
+++ b/command-list.c
@@ -100,7 +100,40 @@ CommandList *build_command_list(Options *op, Package *p)
l = (FileList *) nvalloc(sizeof(FileList));
c = (CommandList *) nvalloc(sizeof(CommandList));
- /* find any possibly conflicting libraries and/or modules */
+ /* find any possibly conflicting modules and/or libraries */
+
+ if (!op->no_kernel_module || op->dkms)
+ find_conflicting_kernel_modules(op, p, l);
+
+ /* check the conflicting file list for any installed kernel modules */
+
+ if (op->kernel_module_only) {
+ if (dkms_module_installed(op, p->version)) {
+ ui_error(op, "A DKMS kernel module with version %s is already "
+ "installed.", p->version);
+ free_file_list(l);
+ free_command_list(op,c);
+ return NULL;
+ }
+
+ for (i = 0; i < l->num; i++) {
+ if (find_installed_file(op, l->filename[i])) {
+ ui_error(op, "The file '%s' already exists as part of this "
+ "driver installation.", l->filename[i]);
+ free_file_list(l);
+ free_command_list(op, c);
+ return NULL;
+ }
+ }
+
+ /* XXX: If installing with --kernel-module-only on a system that has
+ * the kernel module sources already installed, but does NOT have a
+ * built kernel module or DKMS module, duplicate entries for the source
+ * files will be added to the backup log, leading to error messages
+ * when uninstalling the driver later leads to redundant attempts to
+ * delete the files. */
+
+ }
if (!op->kernel_module_only) {
/*
@@ -169,9 +202,6 @@ CommandList *build_command_list(Options *op, Package *p)
#endif /* NV_X86_64 */
}
- if (!op->no_kernel_module)
- find_conflicting_kernel_modules(op, p, l);
-
/*
* find any existing files that clash with what we're going to
* install
@@ -184,20 +214,6 @@ CommandList *build_command_list(Options *op, Package *p)
condense_file_list(p, l);
- /* check the conflicting file list for any installed files */
-
- if (op->kernel_module_only) {
- for (i = 0; i < l->num; i++) {
- if (find_installed_file(op, l->filename[i])) {
- ui_error(op, "The file '%s' already exists as part of this "
- "driver installation.", l->filename[i]);
- free_file_list(l);
- free_command_list(op, c);
- return NULL;
- }
- }
- }
-
/*
* all of the files in the conflicting file list should be backed
* up or deleted
@@ -664,7 +680,7 @@ static void find_conflicting_opengl_libraries(Options *op,
static void find_conflicting_kernel_modules(Options *op,
Package *p, FileList *l)
{
- int i, n = 0;
+ int i = 0, n = 0;
ConflictingFileInfo files[2];
char *paths[3];
char *tmp = get_kernel_name(op);
@@ -672,14 +688,15 @@ static void find_conflicting_kernel_modules(Options *op,
memset(files, 0, sizeof(files));
files[1].name = NULL;
files[1].len = 0;
- paths[0] = op->kernel_module_installation_path;
+ if (op->kernel_module_installation_path) {
+ paths[i++] = op->kernel_module_installation_path;
+ }
if (tmp) {
- paths[1] = nvstrcat("/lib/modules/", tmp, NULL);
- paths[2] = NULL;
- } else {
- paths[1] = NULL;
+ paths[i++] = nvstrcat("/lib/modules/", tmp, NULL);
}
+
+ paths[i] = NULL;
for (i = 0; paths[i]; i++) {
for (n = 0; p->bad_module_filenames[n]; n++) {
diff --git a/common-utils/common-utils.c b/common-utils/common-utils.c
index 98b92fe..a8ee75a 100644
--- a/common-utils/common-utils.c
+++ b/common-utils/common-utils.c
@@ -586,3 +586,63 @@ void fmt(FILE *stream, const char *prefix, const char *fmt, ...)
}
NV_VFORMAT(stream, TRUE, prefix, fmt);
}
+
+
+/*
+ * Read from the given FILE stream until a newline, EOF, or nul
+ * terminator is encountered, writing data into a growable buffer.
+ * The eof parameter is set to TRUE when EOF is encountered. In all
+ * cases, the returned string is null-terminated.
+ *
+ * XXX this function will be rather slow because it uses fgetc() to
+ * pull each character off the stream one at a time; this is done so
+ * that each character can be examined as it's read so that we can
+ * appropriately deal with EOFs and newlines. A better implementation
+ * would use fgets(), but that would still require us to parse each
+ * read line, checking for newlines or guessing if we hit an EOF.
+ */
+char *fget_next_line(FILE *fp, int *eof)
+{
+ char *buf = NULL, *tmpbuf;
+ char *c = NULL;
+ int len = 0, buflen = 0;
+ int ret;
+
+ const int __fget_next_line_len = 32;
+
+ if (eof) {
+ *eof = FALSE;
+ }
+
+ while (1) {
+ if (buflen == len) { /* buffer isn't big enough -- grow it */
+ buflen += __fget_next_line_len;
+ tmpbuf = nvalloc(buflen);
+ if (buf) {
+ memcpy(tmpbuf, buf, len);
+ nvfree(buf);
+ }
+ buf = tmpbuf;
+ c = buf + len;
+ }
+
+ ret = fgetc(fp);
+
+ if ((ret == EOF) && (eof)) {
+ *eof = TRUE;
+ }
+
+ if ((ret == EOF) || (ret == '\n') || (ret == '\0')) {
+ *c = '\0';
+ return buf;
+ }
+
+ *c = (char) ret;
+
+ len++;
+ c++;
+
+ } /* while (1) */
+
+ return NULL; /* should never get here */
+}
diff --git a/common-utils/common-utils.h b/common-utils/common-utils.h
index e0d9314..c5cd411 100644
--- a/common-utils/common-utils.h
+++ b/common-utils/common-utils.h
@@ -65,6 +65,8 @@ void fmterr(const char *fmt, ...);
void fmtwarn(const char *fmt, ...);
void fmt(FILE *stream, const char *prefix, const char *fmt, ...);
+char *fget_next_line(FILE *fp, int *eof);
+
/*
* NV_VSNPRINTF(): macro that assigns buf using vsnprintf(). This is
* correct for differing semantics of the vsnprintf() return value:
diff --git a/common-utils/nvgetopt.c b/common-utils/nvgetopt.c
index f04cef3..1c6c9b8 100644
--- a/common-utils/nvgetopt.c
+++ b/common-utils/nvgetopt.c
@@ -22,6 +22,7 @@
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
+#include <limits.h>
#include "nvgetopt.h"
#include "common-utils.h"
@@ -401,7 +402,7 @@ void nvgetopt_print_help(const NVGetoptOption *options,
* prepend the single character version of the option,
* possibly with an argument; e.g., "-f" or "-f BAR"
*/
- if (isalpha(o->val)) {
+ if (o->val <= UCHAR_MAX && o->val >= 0 && isalpha(o->val)) {
char scratch[16];
char *tmp;
snprintf(scratch, sizeof(scratch), "%c", o->val);
diff --git a/files.c b/files.c
index cfa4516..74d3cea 100644
--- a/files.c
+++ b/files.c
@@ -41,6 +41,7 @@
#include "files.h"
#include "misc.h"
#include "precompiled.h"
+#include "backup.h"
static char *get_xdg_data_dir(void);
@@ -478,24 +479,34 @@ void select_tls_class(Options *op, Package *p)
int set_destinations(Options *op, Package *p)
{
- char *name, *s;
+ char *name;
char *prefix, *dir, *path;
char *xdg_data_dir;
int i;
- s = NULL;
-
+ if (!op->kernel_module_src_dir) {
+ op->kernel_module_src_dir = nvstrcat("nvidia-", p->version, NULL);
+ }
+
for (i = 0; i < p->num_entries; i++) {
switch (p->entries[i].flags & FILE_TYPE_MASK) {
-
+
case FILE_TYPE_KERNEL_MODULE_CMD:
- case FILE_TYPE_KERNEL_MODULE_SRC:
-
- /* we don't install kernel module sources */
-
+ /* we don't install kernel module commands */
p->entries[i].dst = NULL;
continue;
-
+
+ case FILE_TYPE_KERNEL_MODULE_SRC:
+ if (op->no_kernel_module_source) {
+ /* Don't install kernel module source files if requested. */
+ p->entries[i].dst = NULL;
+ continue;
+ }
+ prefix = op->kernel_module_src_prefix;
+ dir = op->kernel_module_src_dir;
+ path = "";
+ break;
+
case FILE_TYPE_OPENGL_LIB:
case FILE_TYPE_OPENGL_SYMLINK:
if (p->entries[i].flags & FILE_CLASS_COMPAT32) {
@@ -649,6 +660,11 @@ int set_destinations(Options *op, Package *p)
continue;
+ case FILE_TYPE_EXPLICIT_PATH:
+ prefix = p->entries[i].path;
+ dir = path = "";
+ break;
+
default:
/*
@@ -860,6 +876,41 @@ int get_prefixes (Options *op)
remove_trailing_slashes(op->utility_prefix);
ui_expert(op, "Utility installation prefix is: '%s'", op->utility_prefix);
+ if (op->expert) {
+ op->no_kernel_module_source =
+ !ui_yes_no(op, !op->no_kernel_module_source,
+ "Do you want to install kernel module sources?");
+ }
+
+ if (!op->no_kernel_module_source) {
+ if (op->expert) {
+ ret = ui_get_input(op, op->kernel_module_src_prefix,
+ "Kernel module source installation prefix");
+ if (ret && ret[0]) {
+ op->kernel_module_src_prefix = ret;
+ if (!confirm_path(op, op->kernel_module_src_prefix))
+ return FALSE;
+ }
+ }
+
+ remove_trailing_slashes(op->kernel_module_src_prefix);
+ ui_expert(op, "Kernel module source installation prefix is: '%s'",
+ op->kernel_module_src_prefix);
+
+ if (op->expert) {
+ ret = ui_get_input(op, op->kernel_module_src_dir,
+ "Kernel module source installation directory");
+ if (ret && ret[0]) {
+ op->kernel_module_src_dir = ret;
+ if (!confirm_path(op, op->kernel_module_src_dir)) return FALSE;
+ }
+ }
+
+ remove_trailing_slashes(op->kernel_module_src_dir);
+ ui_expert(op, "Kernel module source installation directory is: '%s'",
+ op->kernel_module_src_dir);
+ }
+
#if defined(NV_X86_64)
if (op->expert) {
ret = ui_get_input(op, op->compat32_chroot,
@@ -936,7 +987,7 @@ int add_kernel_module_to_package(Options *op, Package *p)
/*
* remove_non_kernel_module_files_from_package() - clear the
* FILE_TYPE_MASK bits for each package entry that is not of type
- * FILE_TYPE_KERNEL_MODULE
+ * FILE_TYPE_KERNEL_MODULE or FILE_TYPE_KERNEL_MODULE_SRC
*/
void remove_non_kernel_module_files_from_package(Options *op, Package *p)
@@ -946,7 +997,8 @@ void remove_non_kernel_module_files_from_package(Options *op, Package *p)
for (i = 0; i < p->num_entries; i++) {
uint64_t flags = p->entries[i].flags & FILE_TYPE_MASK;
if ((flags != FILE_TYPE_KERNEL_MODULE) &&
- (flags != FILE_TYPE_KERNEL_MODULE_CMD))
+ (flags != FILE_TYPE_KERNEL_MODULE_CMD) &&
+ (flags != FILE_TYPE_KERNEL_MODULE_SRC))
p->entries[i].flags &= ~FILE_TYPE_MASK;
}
@@ -1101,13 +1153,15 @@ int confirm_path(Options *op, const char *path)
int mkdir_recursive(Options *op, const char *path, const mode_t mode)
{
- char *c, *tmp, ch;
+ char *c, *tmp, ch, *list, *tmplist;
if (!path || !path[0]) return FALSE;
tmp = nvstrdup(path);
remove_trailing_slashes(tmp);
-
+
+ list = NULL;
+
c = tmp;
do {
c++;
@@ -1121,11 +1175,21 @@ int mkdir_recursive(Options *op, const char *path, const mode_t mode)
free(tmp);
return FALSE;
}
+ /* Prepend the created directory path to a running list */
+ tmplist = list;
+ list = nvstrcat(tmp, "\n", tmplist, NULL);
+ free(tmplist);
}
*c = ch;
}
} while (*c);
+ /* Log any created directories */
+ if (list) {
+ log_mkdir(op, list);
+ }
+
+ free(list);
free(tmp);
return TRUE;
@@ -2038,6 +2102,10 @@ void get_default_prefixes_and_paths(Options *op)
if (!op->documentation_mandir)
op->documentation_mandir = DEFAULT_MANDIR;
+ if (!op->kernel_module_src_prefix)
+ op->kernel_module_src_prefix = DEFAULT_KERNEL_MODULE_SRC_PREFIX;
+ /* kernel_module_src_dir's default value is set in set_destinations() */
+
} /* get_default_prefixes_and_paths() */
diff --git a/install-from-cwd.c b/install-from-cwd.c
index 5fd8159..c700e70 100644
--- a/install-from-cwd.c
+++ b/install-from-cwd.c
@@ -142,7 +142,25 @@ int install_from_cwd(Options *op)
/* attempt to build a kernel module for the target kernel */
if (!op->no_kernel_module) {
- if (!install_kernel_module(op, p)) goto failed;
+
+ /* Offer the DKMS option if DKMS exists and the kernel module sources
+ * will be installed somewhere */
+
+ if (find_system_util("dkms") && !op->no_kernel_module_source) {
+ op->dkms = ui_yes_no(op, op->dkms,
+ "Would you like to register the kernel module "
+ "sources with DKMS? This will allow DKMS to "
+ "automatically build a new module, if you "
+ "install a different kernel later.");
+ }
+
+ /* Only do the normal kernel module install if not using DKMS */
+
+ if (op->dkms) {
+ op->no_kernel_module = TRUE;
+ } else if (!install_kernel_module(op, p)) {
+ goto failed;
+ }
} else {
ui_warn(op, "You specified the '--no-kernel-module' command line "
"option, nvidia-installer will not install a kernel "
@@ -151,6 +169,15 @@ int install_from_cwd(Options *op)
"an earlier NVIDIA driver installation. Please ensure "
"that an NVIDIA kernel module matching this driver version "
"is installed seperately.");
+
+ /* no_kernel_module should imply no DKMS */
+
+ if (op->dkms) {
+ ui_warn(op, "You have specified both the '--no-kernel-module' "
+ "and the '--dkms' command line options. The '--dkms' "
+ "option will be ignored.");
+ op->dkms = FALSE;
+ }
}
/*
@@ -243,6 +270,11 @@ int install_from_cwd(Options *op)
if (!do_install(op, p, c)) goto failed;
+ /* Register, build, and install the module with DKMS, if requested */
+
+ if (op->dkms && !dkms_install_module(op, p->version, get_kernel_name(op)))
+ goto failed;
+
/* run the distro postinstall script */
run_distro_hook(op, "post-install");
@@ -699,6 +731,8 @@ static Package *parse_manifest (Options *op)
p->entries[n].flags |= FILE_TYPE_DOCUMENTATION;
else if (strcmp(flag, "MANPAGE") == 0)
p->entries[n].flags |= FILE_TYPE_MANPAGE;
+ else if (strcmp(flag, "EXPLICIT_PATH") == 0)
+ p->entries[n].flags |= FILE_TYPE_EXPLICIT_PATH;
else if (strcmp(flag, "OPENGL_SYMLINK") == 0)
p->entries[n].flags |= FILE_TYPE_OPENGL_SYMLINK;
else if (strcmp(flag, "CUDA_SYMLINK") == 0)
diff --git a/misc.c b/misc.c
index 6412273..1f1704d 100644
--- a/misc.c
+++ b/misc.c
@@ -214,64 +214,6 @@ int adjust_cwd(Options *op, const char *program_name)
} /* adjust_cwd() */
-
-/*
- * fget_next_line() - read from the given FILE stream until a newline,
- * EOF, or null terminator is encountered, writing data into a
- * growable buffer. The eof parameter is set to TRUE when EOF is
- * encountered. In all cases, the returned string is null-terminated.
- *
- * XXX this function will be rather slow because it uses fgetc() to
- * pull each character off the stream one at a time; this is done so
- * that each character can be examined as it's read so that we can
- * appropriately deal with EOFs and newlines. A better implementation
- * would use fgets(), but that would still require us to parse each
- * read line, checking for newlines or guessing if we hit an EOF.
- */
-
-char *fget_next_line(FILE *fp, int *eof)
-{
- char *buf = NULL, *tmpbuf;
- char *c = NULL;
- int len = 0, buflen = 0;
-
- if (eof) *eof = FALSE;
-
- while (1) {
- if (buflen == len) { /* buffer isn't big enough -- grow it */
- buflen += NV_LINE_LEN;
- tmpbuf = (char *) nvalloc (buflen);
- if (!tmpbuf) {
- if (buf) nvfree(buf);
- return NULL;
- }
- if (buf) {
- memcpy (tmpbuf, buf, len);
- nvfree(buf);
- }
- buf = tmpbuf;
- c = buf + len;
- }
-
- *c = fgetc(fp);
-
- if ((*c == EOF) && (eof)) *eof = TRUE;
- if ((*c == EOF) || (*c == '\n') || (*c == '\0')) {
- *c = '\0';
- return buf;
- }
-
- len++;
- c++;
-
- } /* while (1) */
-
- return NULL; /* should never get here */
-
-} /* fget_next_line() */
-
-
-
/*
* get_next_line() - this function scans for the next newline,
* carriage return, NUL terminator, or EOF in buf. If non-NULL, the
@@ -1356,7 +1298,8 @@ uint64_t get_installable_file_mask(Options *op)
{
uint64_t installable_files = FILE_TYPE_INSTALLABLE_FILE;
if (!op->opengl_headers) installable_files &= ~FILE_TYPE_OPENGL_HEADER;
-
+ if (op->no_kernel_module_source)
+ installable_files &= ~FILE_TYPE_KERNEL_MODULE_SRC;
return installable_files;
} /* get_installable_file_mask() */
@@ -2627,3 +2570,131 @@ int check_for_nouveau(Options *op)
return FALSE;
}
+
+#define DKMS_STATUS " status"
+#define DKMS_ADD " add"
+#define DKMS_BUILD " build"
+#define DKMS_INSTALL " install"
+#define DKMS_REMOVE " remove"
+
+/*
+ * Run the DKMS tool with the provided arguments. The following operations
+ * are supported:
+ *
+ * DKMS_STATUS:
+ * Check the status of the specified module.
+ * DKMS_ADD: requires version
+ * Adds the module to the DKMS database.
+ * DKMS_BUILD: requires version
+ * Builds the module against the currently running kernel.
+ * DKMS_INSTALL: requires version
+ * Installs the module for the currently running kernel.
+ * DKMS_REMOVE: reqires version
+ * Removes the module from all kernels.
+ *
+ * run_dkms returns TRUE if dkms is found and exits with status 0 when run;
+ * FALSE if dkms can't be found, or exits with non-0 status.
+ */
+static int run_dkms(Options *op, const char* verb, const char *version,
+ const char *kernel, char** out)
+{
+ char *cmd, *cmdline, *veropt, *kernopt = NULL, *kernopt_all = "";
+ const char *modopt = " -m nvidia"; /* XXX real name is in the Package */
+ char *output;
+ int ret;
+
+ /* Fail if DKMS not found */
+ cmd = find_system_util("dkms");
+ if (!cmd) {
+ if (strcmp(verb, DKMS_STATUS) != 0) {
+ ui_error(op, "Failed to find dkms on the system!");
+ }
+ return FALSE;
+ }
+
+ /* Convert function parameters into commandline arguments. Optional
+ * arguments may be NULL, in which case nvstrcat() will end early. */
+ veropt = version ? nvstrcat(" -v ", version, NULL) : NULL;
+
+ if (strcmp(verb, DKMS_REMOVE) == 0) {
+ /* Always remove DKMS modules from all kernels to avoid confusion. */
+ kernopt_all = " --all";
+ } else {
+ kernopt = kernel ? nvstrcat(" -k ", kernel, NULL) : NULL;
+ }
+
+ cmdline = nvstrcat(cmd, verb, modopt, veropt, kernopt_all, kernopt, NULL);
+
+ nvfree(cmd);
+
+ /* Run DKMS */
+ ret = run_command(op, cmdline, &output, FALSE, 0, TRUE);
+ if (ret != 0) {
+ ui_error(op, "Failed to run `%s`: %s", cmdline, output);
+ }
+
+ nvfree(cmdline);
+ nvfree(veropt);
+ nvfree(kernopt);
+ if (out) {
+ *out = output;
+ } else {
+ nvfree(output);
+ }
+
+ return ret == 0;
+}
+
+/*
+ * Check to see whether the module is installed via DKMS.
+ * (The version parameter is optional: if NULL, check for any version; if
+ * non-NULL, check for the specified version only.)
+ *
+ * Returns TRUE if DKMS is found, and dkms commandline output is non-empty.
+ * Returns FALSE if DKMS not found, or dkms commandline output is empty.
+ */
+int dkms_module_installed(Options* op, const char *version)
+{
+ int ret, bRet = FALSE;
+ char *output = NULL;
+
+ ret = run_dkms(op, DKMS_STATUS, version, NULL, &output);
+
+ if (output) bRet = strcmp("", output) != 0;
+ nvfree(output);
+
+ return ret && bRet;
+}
+
+/*
+ * Install the given version of the module for the currently running kernel
+ */
+int dkms_install_module(Options *op, const char *version, const char *kernel)
+{
+ ui_status_begin(op, "Installing DKMS kernel module:", "Adding to DKMS");
+ if (!run_dkms(op, DKMS_ADD, version, kernel, NULL)) goto failed;
+
+ ui_status_update(op, .05, "Building module (This may take a moment)");
+ if (!run_dkms(op, DKMS_BUILD, version, kernel, NULL)) goto failed;
+
+ ui_status_update(op, .9, "Installing module");
+ if(!run_dkms(op, DKMS_INSTALL, version, kernel, NULL)) goto failed;
+
+ ui_status_end(op, "done.");
+ return TRUE;
+
+ failed:
+ ui_status_end(op, "error.");
+ ui_error(op, "Failed to install the kernel module through DKMS. No kernel "
+ "module was installed; please try installing again without "
+ "DKMS, or check the DKMS logs for more information.");
+ return FALSE;
+}
+
+/*
+ * Remove the given version of the module on all available kernels.
+ */
+int dkms_remove_module(Options *op, const char *version)
+{
+ return run_dkms(op, DKMS_REMOVE, version, NULL, NULL);
+}
diff --git a/misc.h b/misc.h
index 4a7fcaf..b78e958 100644
--- a/misc.h
+++ b/misc.h
@@ -35,7 +35,6 @@ char *read_next_word (char *buf, char **e);
int check_euid(Options *op);
int check_runlevel(Options *op);
int adjust_cwd(Options *op, const char *program_name);
-char *fget_next_line(FILE *fp, int *eof);
char *get_next_line(char *buf, char **e, char *start, int length);
int run_command(Options *op, const char *cmd, char **data,
int output, int status, int redirect);
@@ -64,5 +63,8 @@ int check_for_nvidia_graphics_devices(Options *op, Package *p);
int run_nvidia_xconfig(Options *op, int restore);
int run_distro_hook(Options *op, const char *hook);
int check_for_nouveau(Options *op);
+int dkms_module_installed(Options *op, const char *version);
+int dkms_install_module(Options *op, const char *version, const char *kernel);
+int dkms_remove_module(Options *op, const char *version);
#endif /* __NVIDIA_INSTALLER_MISC_H__ */
diff --git a/nvidia-installer.c b/nvidia-installer.c
index 2f3d038..3b103be 100644
--- a/nvidia-installer.c
+++ b/nvidia-installer.c
@@ -143,6 +143,8 @@ static Options *load_default_options(void)
op->sigwinch_workaround = TRUE;
op->run_distro_scripts = TRUE;
+ op->no_kernel_module_source = FALSE;
+ op->dkms = FALSE;
return op;
@@ -353,6 +355,7 @@ static void parse_commandline(int argc, char *argv[], Options *op)
case NO_KERNEL_MODULE_OPTION:
op->no_kernel_module = TRUE;
op->kernel_module_only = FALSE; /* conflicts */
+ op->no_kernel_module_source = TRUE;
break;
case NO_X_CHECK_OPTION:
op->no_x_check = TRUE;
@@ -366,6 +369,18 @@ static void parse_commandline(int argc, char *argv[], Options *op)
case NO_OPENGL_FILES_OPTION:
op->no_opengl_files = TRUE;
break;
+ case KERNEL_MODULE_SOURCE_PREFIX_OPTION:
+ op->kernel_module_src_prefix = strval;
+ break;
+ case KERNEL_MODULE_SOURCE_DIR_OPTION:
+ op->kernel_module_src_dir = strval;
+ break;
+ case NO_KERNEL_MODULE_SOURCE_OPTION:
+ op->no_kernel_module_source = TRUE;
+ break;
+ case DKMS_OPTION:
+ op->dkms = TRUE;
+ break;
default:
goto fail;
}
diff --git a/nvidia-installer.h b/nvidia-installer.h
index 816a074..9d1c09a 100644
--- a/nvidia-installer.h
+++ b/nvidia-installer.h
@@ -139,6 +139,8 @@ typedef struct __options {
int run_distro_scripts;
int no_nouveau_check;
int no_opengl_files;
+ int no_kernel_module_source;
+ int dkms;
char *opengl_prefix;
char *opengl_libdir;
@@ -171,6 +173,8 @@ typedef struct __options {
char *kernel_output_path;
char *kernel_include_path;
char *kernel_module_installation_path;
+ char *kernel_module_src_prefix;
+ char *kernel_module_src_dir;
char *utils[MAX_UTILS];
char *proc_mount_point;
@@ -297,7 +301,7 @@ typedef struct __package {
/* Create a symlink only if the file doesn't exist */
#define FILE_TYPE_XMODULE_NEWSYM 0x0000000000100000ULL
#define FILE_TYPE_MANPAGE 0x0000000000200000ULL
-/* unused 0x0000000000400000ULL */
+#define FILE_TYPE_EXPLICIT_PATH 0x0000000000400000ULL
#define FILE_TYPE_CUDA_LIB 0x0000000000800000ULL
#define FILE_TYPE_CUDA_SYMLINK 0x0000000001000000ULL
#define FILE_TYPE_VDPAU_LIB 0x0000000002000000ULL
@@ -330,6 +334,7 @@ typedef struct __package {
FILE_TYPE_UTILITY_LIB | \
FILE_TYPE_DOCUMENTATION | \
FILE_TYPE_MANPAGE | \
+ FILE_TYPE_EXPLICIT_PATH | \
FILE_TYPE_OPENGL_HEADER | \
FILE_TYPE_CUDA_ICD | \
FILE_TYPE_KERNEL_MODULE | \
@@ -340,7 +345,8 @@ typedef struct __package {
FILE_TYPE_GLX_MODULE_SHARED_LIB | \
FILE_TYPE_DOT_DESKTOP | \
FILE_TYPE_VDPAU_LIB | \
- FILE_TYPE_NVCUVID_LIB)
+ FILE_TYPE_NVCUVID_LIB | \
+ FILE_TYPE_KERNEL_MODULE_SRC)
#define FILE_TYPE_HAVE_PATH (FILE_TYPE_XMODULE_SHARED_LIB | \
FILE_TYPE_XMODULE_SYMLINK | \
@@ -348,6 +354,7 @@ typedef struct __package {
FILE_TYPE_GLX_MODULE_SYMLINK | \
FILE_TYPE_XMODULE_NEWSYM | \
FILE_TYPE_MANPAGE | \
+ FILE_TYPE_EXPLICIT_PATH | \
FILE_TYPE_OPENGL_HEADER | \
FILE_TYPE_CUDA_LIB | \
FILE_TYPE_CUDA_SYMLINK | \
@@ -449,6 +456,8 @@ typedef struct __package {
#define DEFAULT_DOCDIR "share/doc"
#define DEFAULT_MANDIR "share/man"
+#define DEFAULT_KERNEL_MODULE_SRC_PREFIX "/usr/src"
+
/*
* As of Xorg 7.x, X components need not be installed relative
* to a special top-level directory, they can be integrated
diff --git a/option_table.h b/option_table.h
index 7f755ee..cfdbd49 100644
--- a/option_table.h
+++ b/option_table.h
@@ -35,7 +35,7 @@
enum {
- XFREE86_PREFIX_OPTION = 1,
+ XFREE86_PREFIX_OPTION = 1024,
OPENGL_PREFIX_OPTION,
OPENGL_LIBDIR_OPTION,
KERNEL_INCLUDE_PATH_OPTION,
@@ -80,6 +80,10 @@ enum {
NO_CC_VERSION_CHECK_OPTION,
NO_DISTRO_SCRIPTS_OPTION,
NO_OPENGL_FILES_OPTION,
+ KERNEL_MODULE_SOURCE_PREFIX_OPTION,
+ KERNEL_MODULE_SOURCE_DIR_OPTION,
+ NO_KERNEL_MODULE_SOURCE_OPTION,
+ DKMS_OPTION,
};
static const NVGetoptOption __options[] = {
@@ -504,6 +508,31 @@ static const NVGetoptOption __options[] = {
{ "no-opengl-files", NO_OPENGL_FILES_OPTION, 0, NULL,
"Do not install any of the OpenGL-related driver files." },
+ { "kernel-module-source-prefix", KERNEL_MODULE_SOURCE_PREFIX_OPTION,
+ NVGETOPT_STRING_ARGUMENT, NULL,
+ "Specify a path where the source directory for the kernel module will "
+ "be installed. Default: install source directory at /usr/src" },
+
+ { "kernel-module-source-dir", KERNEL_MODULE_SOURCE_DIR_OPTION,
+ NVGETOPT_STRING_ARGUMENT, NULL,
+ "Specify the name of the directory where the kernel module sources will "
+ "be installed. Default: directory name is \"nvidia-VERSION\""},
+
+ { "no-kernel-module-source", NO_KERNEL_MODULE_SOURCE_OPTION, 0, NULL,
+ "Skip installation of the kernel module source."},
+
+ { "dkms", DKMS_OPTION, 0, NULL,
+ "nvidia-installer can optionally register the NVIDIA kernel module "
+ "sources, if installed, with DKMS, then build and install a kernel "
+ "module using the DKMS-registered sources. This will allow the DKMS "
+ "infrastructure to automatically build a new kernel module when "
+ "changing kernels. During installation, if DKMS is detected, "
+ "nvidia-installer will ask the user if they wish to register the "
+ "module with DKMS; the default response is 'no'. Use this option to "
+ "make the default response 'yes'. This is useful with the "
+ "'--no-questions' or '--silent' options, which assume the default "
+ "values for all questions." },
+
/* Orphaned options: These options were in the long_options table in
* nvidia-installer.c but not in the help. */
{ "debug", 'd', 0, NULL,NULL },
diff --git a/utils.mk b/utils.mk
index 2a7a9cf..b912f98 100644
--- a/utils.mk
+++ b/utils.mk
@@ -65,6 +65,7 @@ WHOAMI ?= whoami
HOSTNAME_CMD ?= hostname
DATE ?= date
GZIP_CMD ?= gzip
+CHMOD ?= chmod
NV_AUTO_DEPEND ?= 1
NV_VERBOSE ?= 0
@@ -156,6 +157,25 @@ ifndef NVIDIA_VERSION
$(error NVIDIA_VERSION undefined)
endif
+
+##############################################################################
+# Several of the functions below take an argument that indicates if
+# the expression is for the target platform (the system the built
+# program is going to run on) or the host platform (the system
+# performing the build). The argument is either "HOST" or "TARGET"
+# and needs to be converted:
+#
+# "HOST" -> "HOST_"
+# "TARGET" -> ""
+#
+# and prepended to "CC" or "CFLAGS"
+##############################################################################
+
+host_target = $(patsubst HOST,HOST_,$(patsubst TARGET,,$(1)))
+host_target_cc = $(call host_target,$(1))CC
+host_target_cflags = $(call host_target,$(1))CFLAGS
+
+
##############################################################################
# to generate the dependency files, use the compiler's "-MM" option to
# generate output of the form "foo.o : foo.c foo.h"; then, use sed to
@@ -168,13 +188,14 @@ endif
# applies to the object files produced in the build.
#
# Arguments:
-# $(1): CC command (CC or HOST_CC)
+# $(1): whether for host or target platform ("HOST" or "TARGET")
# $(2): source filename
# $(3): object filename
##############################################################################
ifeq ($(NV_AUTO_DEPEND),1)
- AUTO_DEP_CMD = && $($(1)) -MM $$(CFLAGS) $$< | $$(SED) \
+ AUTO_DEP_CMD = && $($(call host_target_cc,$(1))) \
+ -MM $$($(call host_target_cflags,$(1))) $$< | $$(SED) \
-e "s,: ,: $$$$\(wildcard ," \
-e "s,\([^\\]\)$$$$,\1)," \
-e "s;^$$(addsuffix .o,$$(notdir $$(basename $(2)))): ;$(3): ;" \
@@ -249,11 +270,12 @@ BUILD_DEPENDENCY_LIST = \
##############################################################################
# functions to define a rule to build an object file; the first
-# argument is either CC or HOST_CC, the second argument is the source
-# file to compile, and the third argument (_WITH_OBJECT_NAME-only) is
-# the object filename to produce. Example usage:
+# argument whether the rule is for the target or host platform ("HOST"
+# or "TARGET"), the second argument is the source file to compile, and
+# the third argument (_WITH_OBJECT_NAME-only) is the object filename
+# to produce. Example usage:
#
-# $(eval $(call DEFINE_OBJECT_RULE,CC,foo.c))
+# $(eval $(call DEFINE_OBJECT_RULE,TARGET,foo.c))
#
# Note this also attempts to include the dependency file for this
# source file.
@@ -266,7 +288,8 @@ BUILD_DEPENDENCY_LIST = \
define DEFINE_OBJECT_RULE_WITH_OBJECT_NAME
$(3): $(2)
@$(MKDIR) $(OUTPUTDIR)
- $$(call quiet_cmd,$(1)) $$(CFLAGS) -c $$< -o $$@ \
+ $$(call quiet_cmd,$(call host_target_cc,$(1))) \
+ $$($(call host_target_cflags,$(1))) -c $$< -o $$@ \
$(call AUTO_DEP_CMD,$(1),$(2),$(3))
-include $$(call BUILD_DEPENDENCY_LIST,$(3))
diff --git a/version.mk b/version.mk
index 527bb7c..11c1292 100644
--- a/version.mk
+++ b/version.mk
@@ -1 +1 @@
-NVIDIA_VERSION = 302.17
+NVIDIA_VERSION = 304.22