diff options
author | Aaron Plattner <aplattner@nvidia.com> | 2012-07-13 09:47:17 -0700 |
---|---|---|
committer | Aaron Plattner <aplattner@nvidia.com> | 2012-07-13 09:47:17 -0700 |
commit | bd091a2e24f634ea1677785d85ab80eced26d3a8 (patch) | |
tree | 194f1362c5bf2aca13b75e996c6ce3ce66fe5902 | |
parent | 3f8fa13aa46034ade69035ceafcd4f87a0432c3d (diff) |
304.22304.22
-rw-r--r-- | Makefile | 51 | ||||
-rw-r--r-- | backup.c | 119 | ||||
-rw-r--r-- | backup.h | 2 | ||||
-rw-r--r-- | command-list.c | 65 | ||||
-rw-r--r-- | common-utils/common-utils.c | 60 | ||||
-rw-r--r-- | common-utils/common-utils.h | 2 | ||||
-rw-r--r-- | common-utils/nvgetopt.c | 3 | ||||
-rw-r--r-- | files.c | 94 | ||||
-rw-r--r-- | install-from-cwd.c | 36 | ||||
-rw-r--r-- | misc.c | 189 | ||||
-rw-r--r-- | misc.h | 4 | ||||
-rw-r--r-- | nvidia-installer.c | 15 | ||||
-rw-r--r-- | nvidia-installer.h | 13 | ||||
-rw-r--r-- | option_table.h | 31 | ||||
-rw-r--r-- | utils.mk | 37 | ||||
-rw-r--r-- | version.mk | 2 |
16 files changed, 597 insertions, 126 deletions
@@ -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) @@ -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) { @@ -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); @@ -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) @@ -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); +} @@ -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 }, @@ -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)) @@ -1 +1 @@ -NVIDIA_VERSION = 302.17 +NVIDIA_VERSION = 304.22 |