summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Plattner <aplattner@nvidia.com>2013-10-04 08:50:40 -0700
committerAaron Plattner <aplattner@nvidia.com>2013-10-04 08:50:40 -0700
commitf0923811d809b403b23dee449b849a01df6d2e79 (patch)
treea134b5026058e9c621cf359b853d24c67c38cd39
parenta977103d446bc8c0c3827d8726c53bb8292a31cd (diff)
331.13331.13
-rw-r--r--backup.c43
-rw-r--r--command-list.c237
-rw-r--r--common-utils/common-utils.c24
-rw-r--r--common-utils/common-utils.h17
-rw-r--r--common-utils/gen-manpage-opts-helper.c2
-rw-r--r--common-utils/nvgetopt.h4
-rw-r--r--files.c78
-rw-r--r--files.h4
-rw-r--r--install-from-cwd.c151
-rw-r--r--kernel.c787
-rw-r--r--kernel.h5
-rw-r--r--manifest.c2
-rw-r--r--misc.c189
-rw-r--r--misc.h9
-rw-r--r--mkprecompiled.c2
-rw-r--r--ncurses-ui.c498
-rw-r--r--nvidia-installer-ui.h14
-rw-r--r--nvidia-installer.c32
-rw-r--r--nvidia-installer.h12
-rw-r--r--option_table.h25
-rw-r--r--precompiled.c36
-rw-r--r--precompiled.h3
-rw-r--r--stream-ui.c103
-rw-r--r--user-interface.c44
-rw-r--r--user-interface.h2
-rw-r--r--utils.mk2
-rw-r--r--version.mk2
27 files changed, 1546 insertions, 781 deletions
diff --git a/backup.c b/backup.c
index 9030e6f..c8b0eff 100644
--- a/backup.c
+++ b/backup.c
@@ -708,7 +708,7 @@ static int do_uninstall(Options *op, const char *version)
e->filename, strerror(errno));
removal_failed = TRUE;
}
- ui_status_update(op, percent, e->filename);
+ ui_status_update(op, percent, "%s", e->filename);
break;
case INSTALLED_SYMLINK:
@@ -717,7 +717,7 @@ static int do_uninstall(Options *op, const char *version)
e->filename, strerror(errno));
removal_failed = TRUE;
}
- ui_status_update(op, percent, e->filename);
+ ui_status_update(op, percent, "%s", e->filename);
break;
}
}
@@ -763,7 +763,7 @@ static int do_uninstall(Options *op, const char *version)
restore_failed = TRUE;
}
}
- ui_status_update(op, percent, e->filename);
+ ui_status_update(op, percent, "%s", e->filename);
break;
default:
@@ -787,7 +787,7 @@ static int do_uninstall(Options *op, const char *version)
}
}
}
- ui_status_update(op, percent, e->filename);
+ ui_status_update(op, percent, "%s", e->filename);
free(tmpstr);
break;
}
@@ -817,14 +817,35 @@ static int do_uninstall(Options *op, const char *version)
}
/*
- * 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.
+ * attempt to unload the kernel module(s), but don't abort if this fails:
+ * the kernel may not have been configured with support for module
+ * unloading or the user might have unloaded it themselves or the module
+ * might not have existed at all.
*/
+
cmd = nvstrcat(op->utils[RMMOD], " ", RMMOD_MODULE_NAME, NULL);
run_command(op, cmd, NULL, FALSE, 0, TRUE);
nvfree(cmd);
+ for (i = 0; i < NV_MAX_MODULE_INSTANCES; i++) {
+ char num[5];
+ memset(num, 0, sizeof(num));
+ snprintf(num, sizeof(num), "%d", i);
+ num[sizeof(num) - 1] = '\0';
+
+ cmd = nvstrcat(op->utils[RMMOD], " ", RMMOD_MODULE_NAME,
+ num, NULL);
+ run_command(op, cmd, NULL, FALSE, 0, TRUE);
+
+ nvfree(cmd);
+ }
+
+ cmd = nvstrcat(op->utils[RMMOD], " ", RMMOD_MODULE_NAME,
+ "-frontend", NULL);
+ run_command(op, cmd, NULL, FALSE, 0, TRUE);
+
+ nvfree(cmd);
+
run_distro_hook(op, "post-uninstall");
free_backup_info(b);
@@ -1106,7 +1127,7 @@ static int check_backup_log_entries(Options *op, BackupInfo *b)
}
}
}
- ui_status_update(op, percent, e->filename);
+ ui_status_update(op, percent, "%s", e->filename);
break;
@@ -1153,7 +1174,7 @@ static int check_backup_log_entries(Options *op, BackupInfo *b)
free(tmpstr);
}
}
- ui_status_update(op, percent, e->filename);
+ ui_status_update(op, percent, "%s", e->filename);
break;
@@ -1189,7 +1210,7 @@ static int check_backup_log_entries(Options *op, BackupInfo *b)
ret = e->ok = FALSE;
}
}
- ui_status_update(op, percent, tmpstr);
+ ui_status_update(op, percent, "%s", tmpstr);
free(tmpstr);
break;
}
@@ -1607,7 +1628,7 @@ static int sanity_check_backup_log_entries(Options *op, BackupInfo *b)
}
percent = (float) i / (float) (b->n);
- ui_status_update(op, percent, e->filename);
+ ui_status_update(op, percent, "%s", e->filename);
}
ui_status_end(op, "done.");
diff --git a/command-list.c b/command-list.c
index a4d0fc4..45b4f19 100644
--- a/command-list.c
+++ b/command-list.c
@@ -74,6 +74,16 @@ static void add_file_to_list(const char*, const char*, FileList*);
static void append_to_rpm_file_list(Options *op, Command *c);
+/*
+ * find_conflicting_files() optionally takes an array of NoRecursionDirectory
+ * entries to indicate which directories should not be recursively searched.
+ */
+
+typedef struct {
+ int level; /* max search depth: set to negative for unrestricted depth */
+ char *name; /* name to find: NULL to end the list */
+} NoRecursionDirectory;
+
/*
* build_command_list() - construct a list of all the things to do
@@ -151,12 +161,12 @@ CommandList *build_command_list(Options *op, Package *p)
find_conflicting_xfree86_libraries(op, DEFAULT_X_PREFIX, l);
ui_status_update(op, 0.32f, XORG7_DEFAULT_X_PREFIX);
find_conflicting_xfree86_libraries(op, XORG7_DEFAULT_X_PREFIX, l);
- ui_status_update(op, 0.48f, op->x_prefix);
+ ui_status_update(op, 0.48f, "%s", op->x_prefix);
find_conflicting_xfree86_libraries(op, op->x_prefix, l);
- ui_status_update(op, 0.64f, op->x_module_path);
+ ui_status_update(op, 0.64f, "%s", op->x_module_path);
find_conflicting_xfree86_libraries_fullpath(op, op->x_module_path, l);
- ui_status_update(op, 0.80f, op->x_library_path);
+ ui_status_update(op, 0.80f, "%s", op->x_library_path);
find_conflicting_xfree86_libraries_fullpath(op, op->x_library_path, l);
ui_status_end(op, "done.");
@@ -165,11 +175,11 @@ CommandList *build_command_list(Options *op, Package *p)
ui_status_update(op, 0.20f, DEFAULT_X_PREFIX);
find_conflicting_opengl_libraries(op, DEFAULT_X_PREFIX, l);
- ui_status_update(op, 0.40f, op->x_prefix);
+ ui_status_update(op, 0.40f, "%s", op->x_prefix);
find_conflicting_opengl_libraries(op, op->x_prefix, l);
ui_status_update(op, 0.60f, DEFAULT_OPENGL_PREFIX);
find_conflicting_opengl_libraries(op, DEFAULT_OPENGL_PREFIX, l);
- ui_status_update(op, 0.80f, op->opengl_prefix);
+ ui_status_update(op, 0.80f, "%s", op->opengl_prefix);
find_conflicting_opengl_libraries(op, op->opengl_prefix, l);
ui_status_end(op, "done.");
@@ -181,22 +191,22 @@ CommandList *build_command_list(Options *op, Package *p)
ui_status_begin(op, "Searching for conflicting compat32 files:", "Searching");
prefix = nvstrcat(op->compat32_chroot, DEFAULT_X_PREFIX, NULL);
- ui_status_update(op, 0.20f, prefix);
+ ui_status_update(op, 0.20f, "%s", prefix);
find_conflicting_opengl_libraries(op, prefix, l);
nvfree(prefix);
prefix = nvstrcat(op->compat32_chroot, op->x_prefix, NULL);
- ui_status_update(op, 0.40f, prefix);
+ ui_status_update(op, 0.40f, "%s", prefix);
find_conflicting_opengl_libraries(op, prefix, l);
nvfree(prefix);
prefix = nvstrcat(op->compat32_chroot, DEFAULT_OPENGL_PREFIX, NULL);
- ui_status_update(op, 0.60f, prefix);
+ ui_status_update(op, 0.60f, "%s", prefix);
find_conflicting_opengl_libraries(op, prefix, l);
nvfree(prefix);
prefix = nvstrcat(op->compat32_chroot, op->compat32_prefix, NULL);
- ui_status_update(op, 0.80f, prefix);
+ ui_status_update(op, 0.80f, "%s", prefix);
find_conflicting_opengl_libraries(op, prefix, l);
nvfree(prefix);
@@ -457,7 +467,7 @@ int execute_command_list(Options *op, CommandList *c,
int i, ret;
float percent;
- ui_status_begin(op, title, msg);
+ ui_status_begin(op, title, "%s", msg);
for (i = 0; i < c->num; i++) {
@@ -555,6 +565,20 @@ int execute_command_list(Options *op, CommandList *c,
***************************************************************************
*/
+
+/*
+ * CONFLICT_ARCH_ALL: file always conflicts, regardless of arch
+ * CONFLICT_ARCH_32: file only conflicts if its arch is 32 bit
+ * CONFLICT_ARCH_64: file only conflicts if its arch is 64 bit
+ */
+
+typedef enum {
+ CONFLICT_ARCH_ALL,
+ CONFLICT_ARCH_32,
+ CONFLICT_ARCH_64,
+} ConflictArch;
+
+
typedef struct {
const char *name;
int len;
@@ -567,12 +591,15 @@ typedef struct {
*/
const char *requiredString;
+
+ ConflictArch conflictArch;
} ConflictingFileInfo;
static void find_conflicting_files(Options *op,
char *path,
ConflictingFileInfo *files,
- FileList *l);
+ FileList *l,
+ const NoRecursionDirectory *skipdirs);
static void find_conflicting_libraries(Options *op,
const char *prefix,
@@ -580,28 +607,59 @@ static void find_conflicting_libraries(Options *op,
FileList *l);
static ConflictingFileInfo __xfree86_opengl_libs[] = {
- { "libnvidia-glcore.", 17, /* strlen("libnvidia-glcore.") */ NULL },
- { "libGL.", 6, /* strlen("libGL.") */ NULL },
- { "libGLwrapper.", 13, /* strlen("libGLwrapper.") */ NULL },
- { "libglx.", 7, /* strlen("libglx.") */ "glxModuleData" },
- { NULL, 0, NULL }
+ { "libnvidia-glcore.", 17, /* strlen("libnvidia-glcore.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { "libGL.", 6, /* strlen("libGL.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { "libGLwrapper.", 13, /* strlen("libGLwrapper.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { "libglx.", 7, /* strlen("libglx.") */
+ "glxModuleData", CONFLICT_ARCH_ALL },
+
+ /* XXX we do not currently build 64-bit EGL libraries due to problems
+ * with the ABI, so only conflict with 32-bit EGL libraries for now. */
+
+ { "libEGL.", 7, /* strlen("libEGL.") */
+ NULL, CONFLICT_ARCH_32 },
+ { "libGLESv1_CM.", 13, /* strlen("libGLESv1_CM." */
+ NULL, CONFLICT_ARCH_32 },
+ { "libGLESv2.", 10, /* strlen("libGLESv2." */
+ NULL, CONFLICT_ARCH_32 },
+ { NULL, 0, NULL, CONFLICT_ARCH_ALL }
};
static ConflictingFileInfo __xfree86_non_opengl_libs[] = {
- { "nvidia_drv.", 11, /* strlen("nvidia_drv.") */ NULL },
- { "libvdpau.", 9, /* strlen("libvdpau.") */ NULL },
- { "libvdpau_trace.", 15, /* strlen("libvdpau_trace.") */ NULL },
- { "libvdpau_nvidia.", 16, /* strlen("libvdpau_nvidia.") */ NULL },
- { "libnvidia-cfg.", 14, /* strlen("libnvidia-cfg.") */ NULL },
- { "libcuda.", 8, /* strlen("libcuda.") */ NULL },
- { "libnvidia-compiler.", 19, /* strlen("libnvidia-compiler.") */ NULL },
- { "libnvcuvid.", 11, /* strlen("libnvcuvid.") */ NULL },
- { "libnvidia-ml.", 13, /* strlen("libnvidia-ml.") */ NULL },
- { "libnvidia-encode.", 17, /* strlen("libnvidia-encode.") */ NULL },
- { "libnvidia-vgx.", 14, /* strlen("libnvidia-vgx.") */ NULL },
- { "libnvidia-ifr.", 14, /* strlen("libnvidia-ifr.") */ NULL },
- { "libnvidia-vgxcfg.", 17, /* strlen("libnvidia-vgxcfg.") */ NULL },
- { NULL, 0, NULL }
+ { "nvidia_drv.", 11, /* strlen("nvidia_drv.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { "libvdpau_nvidia.", 16, /* strlen("libvdpau_nvidia.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { "libnvidia-cfg.", 14, /* strlen("libnvidia-cfg.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { "libcuda.", 8, /* strlen("libcuda.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { "libnvidia-compiler.", 19, /* strlen("libnvidia-compiler.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { "libnvcuvid.", 11, /* strlen("libnvcuvid.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { "libnvidia-ml.", 13, /* strlen("libnvidia-ml.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { "libnvidia-encode.", 17, /* strlen("libnvidia-encode.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { "libnvidia-vgx.", 14, /* strlen("libnvidia-vgx.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { "libnvidia-ifr.", 14, /* strlen("libnvidia-ifr.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { "libnvidia-vgxcfg.", 17, /* strlen("libnvidia-vgxcfg.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { NULL, 0, NULL, CONFLICT_ARCH_ALL }
+};
+
+static ConflictingFileInfo __xfree86_vdpau_wrapper_libs[] = {
+ { "libvdpau.", 9, /* strlen("libvdpau.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { "libvdpau_trace.", 15, /* strlen("libvdpau_trace.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { NULL, 0, NULL, CONFLICT_ARCH_ALL }
};
/*
@@ -618,6 +676,9 @@ static void find_conflicting_xfree86_libraries(Options *op,
find_conflicting_libraries(op, xprefix, __xfree86_opengl_libs, l);
}
find_conflicting_libraries(op, xprefix, __xfree86_non_opengl_libs, l);
+ if (op->install_vdpau_wrapper == NV_OPTIONAL_BOOL_TRUE) {
+ find_conflicting_libraries(op, xprefix, __xfree86_vdpau_wrapper_libs, l);
+ }
} /* find_conflicting_xfree86_libraries() */
@@ -636,28 +697,39 @@ static void find_conflicting_xfree86_libraries_fullpath(Options *op,
FileList *l)
{
if (!op->no_opengl_files) {
- find_conflicting_files(op, path, __xfree86_opengl_libs, l);
+ find_conflicting_files(op, path, __xfree86_opengl_libs, l, NULL);
+ }
+ find_conflicting_files(op, path, __xfree86_non_opengl_libs, l, NULL);
+ if (op->install_vdpau_wrapper == NV_OPTIONAL_BOOL_TRUE) {
+ find_conflicting_files(op, path, __xfree86_vdpau_wrapper_libs, l, NULL);
}
- find_conflicting_files(op, path, __xfree86_non_opengl_libs, l);
} /* find_conflicting_xfree86_libraries_fullpath() */
static ConflictingFileInfo __opengl_libs[] = {
- { "libnvidia-glcore.", 17, /* strlen("libnvidia-glcore.") */ NULL },
- { "libGL.", 6, /* strlen("libGL.") */ NULL },
- { "libnvidia-tls.", 14, /* strlen("libnvidia-tls.") */ NULL },
- { "libGLwrapper.", 13, /* strlen("libGLwrapper.") */ NULL },
- { NULL, 0, NULL }
+ { "libnvidia-glcore.", 17, /* strlen("libnvidia-glcore.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { "libGL.", 6, /* strlen("libGL.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { "libnvidia-tls.", 14, /* strlen("libnvidia-tls.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { "libGLwrapper.", 13, /* strlen("libGLwrapper.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { NULL, 0, NULL, CONFLICT_ARCH_ALL }
};
static ConflictingFileInfo __non_opengl_libs[] = {
- { "libnvidia-cfg.", 14, /* strlen("libnvidia-cfg.") */ NULL },
- { "libcuda.", 8, /* strlen("libcuda.") */ NULL },
- { "libnvidia-compiler.", 19, /* strlen("libnvidia-compiler.") */ NULL },
- { "libnvidia-ml.", 13, /* strlen("libnvidia-ml.") */ NULL },
- { NULL, 0, NULL }
+ { "libnvidia-cfg.", 14, /* strlen("libnvidia-cfg.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { "libcuda.", 8, /* strlen("libcuda.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { "libnvidia-compiler.", 19, /* strlen("libnvidia-compiler.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { "libnvidia-ml.", 13, /* strlen("libnvidia-ml.") */
+ NULL, CONFLICT_ARCH_ALL },
+ { NULL, 0, NULL, CONFLICT_ARCH_ALL }
};
/*
@@ -692,6 +764,14 @@ static void find_conflicting_kernel_modules(Options *op,
char *paths[3];
char *tmp = get_kernel_name(op);
+ /* Don't descend into the "build" or "source" directories; these won't
+ * contain modules, and may be symlinks back to an actual source tree. */
+ static const NoRecursionDirectory skipdirs[] = {
+ { 1, "build" },
+ { 1, "source" },
+ { 0, NULL }
+ };
+
memset(files, 0, sizeof(files));
files[1].name = NULL;
files[1].len = 0;
@@ -714,7 +794,7 @@ static void find_conflicting_kernel_modules(Options *op,
files[0].name = p->bad_module_filenames[n];
files[0].len = strlen(files[0].name);
- find_conflicting_files(op, paths[i], files, l);
+ find_conflicting_files(op, paths[i], files, l, skipdirs);
}
}
@@ -754,12 +834,14 @@ static void find_existing_files(Package *p, FileList *l,
/*
* ignore_conflicting_file() - ignore (i.e., do not put it on the list
* of files to backup) the conflicting file 'filename' if requiredString
- * is non-NULL and we cannot find the string in 'filename'.
+ * is non-NULL and we cannot find the string in 'filename', or if the
+ * file only conflicts on specific architectures, and the file's
+ * architecture does not match.
*/
static int ignore_conflicting_file(Options *op,
const char *filename,
- const char *requiredString)
+ const ConflictingFileInfo info)
{
int fd = -1;
struct stat stat_buf;
@@ -767,9 +849,29 @@ static int ignore_conflicting_file(Options *op,
int ret = FALSE;
int i, len;
- /* if no requiredString, do not ignore this conflicting file */
+ /* check if the file only conflicts on certain architectures */
+
+ if (info.conflictArch != CONFLICT_ARCH_ALL) {
+ ElfFileType elftype = get_elf_architecture(filename);
+
+ switch (elftype) {
+ case ELF_ARCHITECTURE_32:
+ ret = info.conflictArch != CONFLICT_ARCH_32;
+ break;
+ case ELF_ARCHITECTURE_64:
+ ret = info.conflictArch != CONFLICT_ARCH_64;
+ break;
+ default:
+ ui_warn(op, "Unable to determine the architecture of the file "
+ "'%s', which has an architecture-specific conflict.",
+ filename);
+ break;
+ }
+ }
+
+ /* if no requiredString, do not check for the required string */
- if (!requiredString) return FALSE;
+ if (!info.requiredString) return ret;
if ((fd = open(filename, O_RDONLY)) == -1) {
ui_error(op, "Unable to open '%s' for reading (%s)",
@@ -803,10 +905,10 @@ static int ignore_conflicting_file(Options *op,
ret = TRUE;
- len = strlen(requiredString);
+ len = strlen(info.requiredString);
for (i = 0; (i + len) <= stat_buf.st_size; i++) {
- if ((strncmp(&file[i], requiredString, len) == 0) &&
+ if ((strncmp(&file[i], info.requiredString, len) == 0) &&
(((i + len) == stat_buf.st_size) || (file[i+len] == '\0'))) {
ret = FALSE;
break;
@@ -841,7 +943,8 @@ static int ignore_conflicting_file(Options *op,
static void find_conflicting_files(Options *op,
char *path,
ConflictingFileInfo *files,
- FileList *l)
+ FileList *l,
+ const NoRecursionDirectory *skipdirs)
{
int i;
char *paths[2];
@@ -859,9 +962,10 @@ static void find_conflicting_files(Options *op,
case FTS_F:
case FTS_SLNONE:
for (i = 0; files[i].name; i++) {
+ /* end compare at len e.g. so "libGL." matches "libGL.so.1" */
if (!strncmp(ent->fts_name, files[i].name, files[i].len) &&
!ignore_conflicting_file(op, ent->fts_path,
- files[i].requiredString)) {
+ files[i])) {
add_file_to_list(NULL, ent->fts_path, l);
}
}
@@ -869,14 +973,17 @@ static void find_conflicting_files(Options *op,
case FTS_DP:
case FTS_D:
- if (op->no_recursion ||
- /*
- * stop recursing into any "nvidia-cg-toolkit"
- * directory to prevent libGL.so.1 from being deleted
- * (see bug 843595).
- */
- !strcmp("nvidia-cg-toolkit", ent->fts_name))
+ if (op->no_recursion) {
fts_set(fts, ent, FTS_SKIP);
+ } else if (skipdirs) {
+ const NoRecursionDirectory *dir;
+ for (dir = skipdirs; dir->name; dir++) {
+ if ((dir->level < 0 || dir->level >= ent->fts_level) &&
+ strcmp(ent->fts_name, dir->name) == 0) {
+ fts_set(fts, ent, FTS_SKIP);
+ }
+ }
+ }
break;
default:
@@ -885,7 +992,7 @@ static void find_conflicting_files(Options *op,
* and directories; traversing the hierarchy logically
* to simplify handling of paths with symbolic links
* to directories, we only need to handle broken links
- * and, if recursion was disabled, directories.
+ * and, if recursion was not disabled, directories.
*/
break;
}
@@ -912,6 +1019,16 @@ static void find_conflicting_libraries(Options *op,
int i, j;
char *paths[4];
+ /*
+ * stop recursing into any "nvidia-cg-toolkit"
+ * directory to prevent libGL.so.1 from being deleted
+ * (see bug 843595).
+ */
+ static const NoRecursionDirectory skipdirs[] = {
+ { -1, "nvidia-cg-toolkit" },
+ { 0, NULL }
+ };
+
paths[0] = nvstrcat(prefix, "/", "lib", NULL);
paths[1] = nvstrcat(prefix, "/", "lib64", NULL);
paths[2] = nvstrcat(prefix, "/", "lib32", NULL);
@@ -937,7 +1054,7 @@ static void find_conflicting_libraries(Options *op,
}
}
- if (paths[i]) find_conflicting_files(op, paths[i], files, l);
+ if (paths[i]) find_conflicting_files(op, paths[i], files, l, skipdirs);
}
for (i = 0; i < 3; i++)
diff --git a/common-utils/common-utils.c b/common-utils/common-utils.c
index b2958a7..9bd349e 100644
--- a/common-utils/common-utils.c
+++ b/common-utils/common-utils.c
@@ -235,6 +235,28 @@ char *nvasprintf(const char *fmt, ...)
} /* nvasprintf() */
+/*
+ * nv_append_sprintf() - similar to glib's g_string_append_printf(), except
+ * instead of operating on a GString it operates on a (char **). Appends a
+ * formatted string to the end of the dynamically-allocated string pointed to by
+ * *buf (or the empty string if *buf is NULL), potentially reallocating the
+ * string in the process. This function only returns on succcess.
+ */
+void nv_append_sprintf(char **buf, const char *fmt, ...)
+{
+ char *prefix, *suffix;
+
+ prefix = *buf;
+ NV_VSNPRINTF(suffix, fmt);
+
+ if (!prefix) {
+ *buf = suffix;
+ } else {
+ *buf = nvstrcat(prefix, suffix, NULL);
+ free(prefix);
+ free(suffix);
+ }
+}
/*
@@ -413,7 +435,7 @@ TextRows *nv_format_text_rows(const char *prefix,
}
}
- /* look for any newline inbetween a and b, and move b to it */
+ /* look for any newline between a and b, and move b to it */
for (c = a; c < b; c++) if (*c == '\n') { b = c; break; }
diff --git a/common-utils/common-utils.h b/common-utils/common-utils.h
index 92c57dd..3bc934f 100644
--- a/common-utils/common-utils.h
+++ b/common-utils/common-utils.h
@@ -72,6 +72,7 @@ char *nvstrtolower(char *s);
char *nvstrtoupper(char *s);
char *nvstrchrnul(char *s, int c);
char *nvasprintf(const char *fmt, ...) NV_ATTRIBUTE_PRINTF(1, 2);
+void nv_append_sprintf(char **buf, const char *fmt, ...) NV_ATTRIBUTE_PRINTF(2, 3);
void nvfree(void *s);
char *tilde_expansion(const char *str);
@@ -184,4 +185,20 @@ static NV_INLINE uint64_t nv_encode_version(unsigned int major,
#define NV_VERSION4(major, minor, micro, nano) \
nv_encode_version(major, minor, micro, nano)
+/*
+ * Helper enum that can be used for boolean values that might or might not be
+ * set. Care should be taken to avoid simple boolean testing, as a value of
+ * NV_OPTIONAL_BOOL_DEFAULT would evaluate as true.
+ *
+ * The user is responsible for unconditionally initializing the default value of
+ * any such booleans to NV_OPTIONAL_BOOL_DEFAULT, before any code path that
+ * might optionally set their values is executed.
+ */
+
+typedef enum {
+ NV_OPTIONAL_BOOL_DEFAULT = -1,
+ NV_OPTIONAL_BOOL_FALSE = FALSE,
+ NV_OPTIONAL_BOOL_TRUE = TRUE
+} NVOptionalBool;
+
#endif /* __COMMON_UTILS_H__ */
diff --git a/common-utils/gen-manpage-opts-helper.c b/common-utils/gen-manpage-opts-helper.c
index d2abb1c..532015d 100644
--- a/common-utils/gen-manpage-opts-helper.c
+++ b/common-utils/gen-manpage-opts-helper.c
@@ -89,7 +89,7 @@ static void print_option(const NVGetoptOption *o)
* '^' : toggles bold on and off
* '-' : is backslashified: "\-"
*
- * Whitespace is omited when italics or bold is on
+ * Whitespace is omitted when italics or bold is on
*/
italics = 0;
diff --git a/common-utils/nvgetopt.h b/common-utils/nvgetopt.h
index 5847546..fc735ee 100644
--- a/common-utils/nvgetopt.h
+++ b/common-utils/nvgetopt.h
@@ -34,8 +34,8 @@
/*
* indicates that the option is a boolean value; the presence of the
- * option will be interpretted as a TRUE value; if the option is
- * prepended with '--no-', the option will be interpretted as a FALSE
+ * option will be interpreted as a TRUE value; if the option is
+ * prepended with '--no-', the option will be interpreted as a FALSE
* value. On success, nvgetopt will return the parsed boolean value
* through 'boolval'.
*/
diff --git a/files.c b/files.c
index 6271205..d421c38 100644
--- a/files.c
+++ b/files.c
@@ -505,6 +505,8 @@ int set_destinations(Options *op, Package *p)
case FILE_TYPE_VDPAU_LIB:
case FILE_TYPE_VDPAU_SYMLINK:
+ case FILE_TYPE_VDPAU_WRAPPER_LIB:
+ case FILE_TYPE_VDPAU_WRAPPER_SYMLINK:
if (p->entries[i].compat_arch == FILE_COMPAT_ARCH_COMPAT32) {
prefix = op->compat32_prefix;
dir = op->compat32_libdir;
@@ -975,26 +977,30 @@ int get_prefixes (Options *op)
} /* get_prefixes() */
-
/*
- * add_kernel_module_to_package() - append the kernel module
- * (contained in p->kernel_module_build_directory) to the package list
- * for installation.
+ * add_kernel_module_helper() - append a kernel module (contained in
+ * p->kernel_module_build_directory/subdir) to the package list.
*/
-int add_kernel_module_to_package(Options *op, Package *p)
+static void add_kernel_module_helper(Options *op, Package *p,
+ const char *filename, const char *subdir)
{
char *file, *name, *dst;
- file = nvstrcat(p->kernel_module_build_directory, "/",
- p->kernel_module_filename, NULL);
+ file = nvstrcat(p->kernel_module_build_directory, "/", subdir,
+ filename, NULL);
name = strrchr(file, '/');
- if (name) name++;
- if (!name) name = file;
- dst = nvstrcat(op->kernel_module_installation_path, "/",
- p->kernel_module_filename, NULL);
+ if (name && name[0]) {
+ name++;
+ }
+
+ if (!name || !name[0]) {
+ name = file;
+ }
+
+ dst = nvstrcat(op->kernel_module_installation_path, "/", filename, NULL);
add_package_entry(p,
file,
@@ -1004,7 +1010,36 @@ int add_kernel_module_to_package(Options *op, Package *p)
dst,
FILE_TYPE_KERNEL_MODULE,
FILE_TLS_CLASS_NONE,
+ FILE_COMPAT_ARCH_NONE,
0644);
+}
+
+/*
+ * add_kernel_modules_to_package() - add any to-be-installed kernel modules
+ * to the package list for installation.
+ */
+
+int add_kernel_modules_to_package(Options *op, Package *p)
+{
+ int i;
+
+ if (op->multiple_kernel_modules) {
+ add_kernel_module_helper(op, p, p->kernel_frontend_module_filename, "");
+ }
+
+ for (i = 0; i < op->num_kernel_modules; i++) {
+
+ char *tmp, *name;
+
+ name = nvstrdup(p->kernel_module_filename);
+
+ tmp = strrchr(name, '0');
+ if (tmp) *tmp = *tmp + i;
+
+ add_kernel_module_helper(op, p, name, "");
+
+ nvfree(name);
+ }
return TRUE;
@@ -1013,8 +1048,8 @@ int add_kernel_module_to_package(Options *op, Package *p)
/*
- * Clear the file type for each package entry that is not type
- * FILE_TYPE_KERNEL_MODULE or FILE_TYPE_KERNEL_MODULE_SRC.
+ * Invalidate each package entry that is not type
+ * FILE_TYPE_KERNEL_MODULE{,_CMD,_SRC}.
*/
void remove_non_kernel_module_files_from_package(Options *op, Package *p)
@@ -1032,7 +1067,7 @@ void remove_non_kernel_module_files_from_package(Options *op, Package *p)
/*
- * Clear the file type for each package entry that is an OpenGL File
+ * Invalidate each package entry that is an OpenGL file
*/
void remove_opengl_files_from_package(Options *op, Package *p)
{
@@ -1952,6 +1987,7 @@ void process_libGL_la_files(Options *op, Package *p)
NULL, /* dst */
FILE_TYPE_LIBGL_LA,
p->entries[i].tls_class,
+ p->entries[i].compat_arch,
p->entries[i].mode);
}
@@ -2027,6 +2063,7 @@ void process_dot_desktop_files(Options *op, Package *p)
NULL, /* dst */
FILE_TYPE_DOT_DESKTOP,
p->entries[i].tls_class,
+ p->entries[i].compat_arch,
p->entries[i].mode);
}
}
@@ -2283,13 +2320,6 @@ static int get_x_paths_helper(Options *op,
/*
* attempt to determine the path through the various query mechanisms
- *
- * xorg-server >= 1.3 has a stupid version number regression because the
- * reported Xorg version was tied to the server version, meaning what used
- * to report 7.2 now reports, for example, 1.2.99.903. This means we set
- * op->modular_xorg to FALSE. However, any server with this regression will
- * also support the -showDefaultModulePath option so we should still be able
- * to get the right path.
*/
/*
@@ -2464,7 +2494,7 @@ static void get_x_library_and_module_paths(Options *op)
* at the given path, keep reprompting until a valid path to a regular file or
* symbolic link is given. This is just a thin wrapper around ui_get_input().
*/
-char *get_filename(Options *op, const char *def, const char *fmt, ...)
+char *get_filename(Options *op, const char *def, const char *msg)
{
struct stat stat_buf;
char *file = NULL;
@@ -2476,7 +2506,7 @@ char *get_filename(Options *op, const char *def, const char *fmt, ...)
return nvstrdup(def);
}
- file = ui_get_input(op, file ? file : def, fmt);
+ file = ui_get_input(op, file ? file : def, "%s", msg);
while (stat(file, &stat_buf) == -1 ||
!(S_ISREG(stat_buf.st_mode) || S_ISLNK(stat_buf.st_mode))) {
@@ -2485,7 +2515,7 @@ char *get_filename(Options *op, const char *def, const char *fmt, ...)
ui_message(op, "File \"%s\" does not exist, or is not a regular "
"file. Please enter another filename.", file);
- file = ui_get_input(op, oldfile ? oldfile : def, fmt);
+ file = ui_get_input(op, oldfile ? oldfile : def, "%s", msg);
nvfree(oldfile);
}
diff --git a/files.h b/files.h
index 314fb8a..42ef924 100644
--- a/files.h
+++ b/files.h
@@ -33,7 +33,7 @@ void select_tls_class(Options *op, Package *p); /* XXX move? */
int set_destinations(Options *op, Package *p); /* XXX move? */
int get_license_acceptance(Options *op); /* XXX move? */
int get_prefixes(Options *op); /* XXX move? */
-int add_kernel_module_to_package(Options *op, Package *p);
+int add_kernel_modules_to_package(Options *op, Package *p);
void remove_non_kernel_module_files_from_package(Options *op, Package *p);
void remove_opengl_files_from_package(Options *op, Package *p);
void remove_trailing_slashes(char *s);
@@ -65,7 +65,7 @@ void process_dot_desktop_files(Options *op, Package *p);
int set_security_context(Options *op, const char *filename);
void get_default_prefixes_and_paths(Options *op);
char *nv_strreplace(char *src, char *orig, char *replace);
-char *get_filename(Options *op, const char *def, const char *fmt, ...) NV_ATTRIBUTE_PRINTF(3, 4);
+char *get_filename(Options *op, const char *def, const char *msg);
int secure_delete(Options *op, const char *file);
void invalidate_package_entry(PackageEntry *entry);
diff --git a/install-from-cwd.c b/install-from-cwd.c
index 9803a0f..19e6b84 100644
--- a/install-from-cwd.c
+++ b/install-from-cwd.c
@@ -96,7 +96,7 @@ int install_from_cwd(Options *op)
*/
if ((p = parse_manifest(op)) == NULL) goto failed;
-
+
ui_set_title(op, "%s (%s)", p->description, p->version);
/*
@@ -153,25 +153,7 @@ int install_from_cwd(Options *op)
/* attempt to build a kernel module for the target kernel */
if (!op->no_kernel_module) {
-
- /* Offer the DKMS option if DKMS exists and the kernel module sources
- * will be installed somewhere. Don't offer DKMS as an option if module
- * signing was requested. */
-
- if (find_system_util("dkms") && !op->no_kernel_module_source &&
- !(op->module_signing_secret_key && op->module_signing_public_key)) {
- 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)) {
+ if (!install_kernel_module(op, p)) {
goto failed;
}
} else {
@@ -263,6 +245,14 @@ int install_from_cwd(Options *op)
if (!uninstall_existing_driver(op, FALSE)) goto failed;
}
+ /*
+ * Determine whether the VDPAU wrapper should be installed: this must be
+ * done after uninstallation of the previous driver, to avoid detecting a
+ * leftover wrapper, and before building the command list.
+ */
+
+ should_install_vdpau_wrapper(op, p);
+
/* build a list of operations to execute to do the install */
if ((c = build_command_list(op, p)) == NULL) goto failed;
@@ -397,6 +387,26 @@ static int install_kernel_module(Options *op, Package *p)
{
PrecompiledInfo *precompiled_info;
+ /* Offer the DKMS option if DKMS exists and the kernel module sources
+ * will be installed somewhere. Don't offer DKMS as an option if module
+ * signing was requested. */
+
+ if (find_system_util("dkms") && !op->no_kernel_module_source &&
+ !(op->module_signing_secret_key && op->module_signing_public_key)) {
+ 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;
+ return TRUE;
+ }
+
/* determine where to install the kernel module */
if (!determine_kernel_module_installation_path(op)) return FALSE;
@@ -420,9 +430,12 @@ static int install_kernel_module(Options *op, Package *p)
if ((precompiled_info = find_precompiled_kernel_interface(op, p))) {
+ int i;
+
+
/*
- * we have a prebuilt kernel interface, so now link the kernel
- * interface with the binary portion of the kernel module.
+ * we have a prebuilt kernel interface package, so now link the
+ * kernel interface files to produce the kernel module.
*
* XXX if linking fails, maybe we should fall through and
* attempt to build the kernel module? No, if linking fails,
@@ -430,8 +443,6 @@ static int install_kernel_module(Options *op, Package *p)
* abort.
*/
- int i;
-
for (i = 0; i < precompiled_info->num_files; i++) {
if (!link_kernel_module(op, p, p->kernel_module_build_directory,
&(precompiled_info->files[i]))) {
@@ -477,9 +488,9 @@ static int install_kernel_module(Options *op, Package *p)
if (!test_kernel_module(op, p)) return FALSE;
- /* add the kernel module to the list of things to install */
+ /* add the kernel modules to the list of things to install */
- if (!add_kernel_module_to_package(op, p)) return FALSE;
+ if (!add_kernel_modules_to_package(op, p)) return FALSE;
return TRUE;
}
@@ -495,7 +506,7 @@ int add_this_kernel(Options *op)
{
Package *p;
PrecompiledFileInfo *fileInfos;
- int num_files;
+ int num_expected_files = 1;
/* parse the manifest */
@@ -505,14 +516,17 @@ int add_this_kernel(Options *op)
if (!determine_kernel_source_path(op, p)) goto failed;
+ if (op->multiple_kernel_modules)
+ num_expected_files = op->num_kernel_modules + 1;
+
/* build the precompiled files */
- num_files = build_kernel_interface(op, p, &fileInfos);
- if (!num_files) goto failed;
+ if (num_expected_files != build_kernel_interface(op, p, &fileInfos))
+ goto failed;
/* pack the precompiled files */
- if (!pack_precompiled_files(op, p, num_files, fileInfos))
+ if (!pack_precompiled_files(op, p, num_expected_files, fileInfos))
goto failed;
free_package(p);
@@ -564,7 +578,7 @@ int add_this_kernel(Options *op)
static Package *parse_manifest (Options *op)
{
- char *buf, *c, *flag , *tmpstr;
+ char *buf, *c, *flag, *tmpstr, *module_suffix = "";
int done, n, line;
int fd, ret, len = 0;
struct stat stat_buf, entry_stat_buf;
@@ -601,17 +615,30 @@ static Package *parse_manifest (Options *op)
p->version = get_next_line(ptr, &ptr, manifest, len);
if (!p->version) goto invalid_manifest_file;
- /* new third line is the kernel interface filename */
+ /* Ignore the third line */
line++;
- p->kernel_interface_filename = get_next_line(ptr, &ptr, manifest, len);
- if (!p->kernel_interface_filename) goto invalid_manifest_file;
+ nvfree(get_next_line(ptr, &ptr, manifest, len));
/* the fourth line is the kernel module name */
line++;
- p->kernel_module_name = get_next_line(ptr, &ptr, manifest, len);
- if (!p->kernel_module_name) goto invalid_manifest_file;
+ tmpstr = get_next_line(ptr, &ptr, manifest, len);
+ if (!tmpstr) goto invalid_manifest_file;
+
+ if (op->multiple_kernel_modules) {
+ module_suffix = "0";
+ p->kernel_frontend_module_name = nvstrcat(tmpstr, "-frontend", NULL);
+ p->kernel_frontend_module_filename =
+ nvstrcat(p->kernel_frontend_module_name, ".ko", NULL);
+ p->kernel_frontend_interface_filename = nvstrdup("nv-linuxfrontend.o");
+ }
+
+ p->kernel_module_name = nvstrcat(tmpstr, module_suffix, NULL);
+ p->kernel_module_filename = nvstrcat(p->kernel_module_name, ".ko", NULL);
+ p->kernel_interface_filename = nvstrcat("nv-linux", module_suffix, ".o", NULL);
+
+ nvfree(tmpstr);
/*
* the fifth line is a whitespace-separated list of kernel modules
@@ -870,6 +897,7 @@ void add_package_entry(Package *p,
char *dst,
PackageEntryFileType type,
PackageEntryFileTlsClass tls_class,
+ PackageEntryFileCompatArch compat_arch,
mode_t mode)
{
int n;
@@ -882,15 +910,16 @@ void add_package_entry(Package *p,
memset(&p->entries[n], 0, sizeof(PackageEntry));
- p->entries[n].file = file;
- p->entries[n].path = path;
- p->entries[n].name = name;
- p->entries[n].target = target;
- p->entries[n].dst = dst;
- p->entries[n].type = type;
- p->entries[n].tls_class = tls_class;
- p->entries[n].mode = mode;
- p->entries[n].caps = get_file_type_capabilities(type);
+ p->entries[n].file = file;
+ p->entries[n].path = path;
+ p->entries[n].name = name;
+ p->entries[n].target = target;
+ p->entries[n].dst = dst;
+ p->entries[n].type = type;
+ p->entries[n].tls_class = tls_class;
+ p->entries[n].mode = mode;
+ p->entries[n].caps = get_file_type_capabilities(type);
+ p->entries[n].compat_arch = compat_arch;
if (stat(p->entries[n].file, &stat_buf) != -1) {
p->entries[n].inode = stat_buf.st_ino;
@@ -954,6 +983,10 @@ static void free_package(Package *p)
nvfree((char *) p->entries);
+ nvfree(p->kernel_frontend_module_filename);
+ nvfree(p->kernel_frontend_module_name);
+ nvfree(p->kernel_frontend_interface_filename);
+
nvfree((char *) p);
} /* free_package() */
@@ -966,7 +999,7 @@ static void free_package(Package *p)
static int assisted_module_signing(Options *op, Package *p)
{
- int generate_keys = FALSE, do_sign = FALSE, secureboot;
+ int generate_keys = FALSE, do_sign = FALSE, secureboot, i;
secureboot = secure_boot_enabled();
@@ -1148,9 +1181,27 @@ guess_fail:
}
/* Now that we have keys (user-supplied or installer-generated),
- * sign the kernel module which we built earlier. */
- if (!sign_kernel_module(op, p->kernel_module_build_directory, TRUE)) {
- return FALSE;
+ * sign the kernel module/s which we built earlier. */
+
+ for (i = 0; i < op->num_kernel_modules; i++) {
+ char module_instance_str[5];
+ memset(module_instance_str, 0, sizeof(module_instance_str));
+
+ if (op->multiple_kernel_modules) {
+ snprintf(module_instance_str, sizeof(module_instance_str), "%d", i);
+ }
+
+ if (!sign_kernel_module(op, p->kernel_module_build_directory,
+ module_instance_str, TRUE)) {
+ return FALSE;
+ }
+ }
+
+ if (op->multiple_kernel_modules) {
+ if (!sign_kernel_module(op, p->kernel_module_build_directory,
+ "frontend", TRUE)) {
+ return FALSE;
+ }
}
if (generate_keys) {
@@ -1224,6 +1275,7 @@ guess_fail:
NULL, /* dst */
FILE_TYPE_MODULE_SIGNING_KEY,
FILE_TLS_CLASS_NONE,
+ FILE_COMPAT_ARCH_NONE,
0444);
ui_message(op, "An X.509 certificate containing the public signing "
@@ -1256,6 +1308,7 @@ guess_fail:
NULL, /* dst */
FILE_TYPE_MODULE_SIGNING_KEY,
FILE_TLS_CLASS_NONE,
+ FILE_COMPAT_ARCH_NONE,
0400);
ui_message(op, "The private signing key will be installed to %s/%s. "
diff --git a/kernel.c b/kernel.c
index 13b2dbc..0237cdd 100644
--- a/kernel.c
+++ b/kernel.c
@@ -53,23 +53,25 @@ static int check_for_loaded_kernel_module(Options *op, const char *);
static void check_for_warning_messages(Options *op);
static int rmmod_kernel_module(Options *op, const char *);
static PrecompiledInfo *download_updated_kernel_interface(Options*, Package*,
- const char*);
+ const char*,
+ char* const*);
static int fbdev_check(Options *op, Package *p);
static int xen_check(Options *op, Package *p);
static int preempt_rt_check(Options *op, Package *p);
static PrecompiledInfo *scan_dir(Options *op, Package *p,
const char *directory_name,
- const char *proc_version_string);
+ const char *proc_version_string,
+ char *const *search_filelist);
static char *build_distro_precompiled_kernel_interface_dir(Options *op);
static char *convert_include_path_to_source_path(const char *inc);
-static char *guess_kernel_module_filename(Options *op);
static char *get_machine_arch(Options *op);
static int init_libkmod(void);
static void close_libkmod(void);
static int run_conftest(Options *op, Package *p, const char *args,
char **result);
+static void replace_zero(char* filename, int i);
/* libkmod handle and function pointers */
static void *libkmod = NULL;
@@ -80,6 +82,7 @@ static int (*lkmod_module_new_from_path)(struct kmod_ctx*, const char*,
struct kmod_module**) = NULL;
static int (*lkmod_module_insert_module)(struct kmod_module*, unsigned int,
const char*) = NULL;
+static void free_search_filelist(char **);
/*
* Message text that is used by several error messages.
@@ -423,23 +426,24 @@ int determine_kernel_output_path(Options *op)
* the linked module and append the signature.
*/
static int attach_signature(Options *op, Package *p,
- const PrecompiledFileInfo *fileInfo) {
+ const PrecompiledFileInfo *fileInfo,
+ const char *module_name) {
uint32 actual_crc;
- char *module_filename;
+ char *module_path;
int ret = FALSE, command_ret;
ui_log(op, "Attaching module signature to linked kernel module.");
- module_filename = nvstrcat(p->kernel_module_build_directory, "/",
- p->kernel_module_filename, NULL);
+ module_path = nvstrcat(p->kernel_module_build_directory, "/",
+ module_name, NULL);
- command_ret = verify_crc(op, module_filename, fileInfo->linked_module_crc,
+ command_ret = verify_crc(op, module_path, fileInfo->linked_module_crc,
&actual_crc);
if (command_ret) {
FILE *module_file;
- module_file = fopen(module_filename, "a+");
+ module_file = fopen(module_path, "a+");
if (module_file && fileInfo->signature_size) {
command_ret = fwrite(fileInfo->signature, 1,
@@ -485,11 +489,27 @@ attach_done:
ui_error(op, "Failed to attach signature.");
}
- nvfree(module_filename);
+ nvfree(module_path);
return ret;
} /* attach_signature() */
+/*
+ * Look for the presence of char '0' in filename and replace
+ * it with the integer value passed as input. This is used
+ * especially for multiple kernel module builds.
+ */
+
+static void replace_zero(char *filename, int i)
+{
+ char *name;
+
+ if (i < 0 || i > 9) return;
+
+ name = strrchr(filename, '0');
+ if (name) *name = *name + i;
+}
+
/*
* link_kernel_module() - link the prebuilt kernel interface against
@@ -519,14 +539,12 @@ int link_kernel_module(Options *op, Package *p, const char *build_directory,
return FALSE;
}
- p->kernel_module_filename = guess_kernel_module_filename(op);
-
cmd = nvstrcat("cd ", build_directory, "; ", op->utils[LD], " ",
LD_OPTIONS, " -o ", fileInfo->linked_module_name, " ",
fileInfo->name, " ", fileInfo->core_object_name, NULL);
-
+
ret = run_command(op, cmd, &result, TRUE, 0, TRUE);
-
+
free(cmd);
if (ret != 0) {
@@ -540,7 +558,8 @@ int link_kernel_module(Options *op, Package *p, const char *build_directory,
PRECOMPILED_ATTR(LINKED_MODULE_CRC);
if ((fileInfo->attributes & attrmask) == attrmask) {
- return attach_signature(op, p, fileInfo);
+ return attach_signature(op, p, fileInfo,
+ fileInfo->linked_module_name);
}
return TRUE;
@@ -548,6 +567,62 @@ int link_kernel_module(Options *op, Package *p, const char *build_directory,
} /* link_kernel_module() */
+
+static int build_kernel_module_helper(Options *op, const char *dir,
+ const char *module, int num_instances)
+{
+ int ret;
+ char *instances = NULL, *cmd, *tmp;
+
+ tmp = op->multiple_kernel_modules && num_instances ?
+ nvasprintf("%d", num_instances) : NULL;
+ instances = nvstrcat(" NV_BUILD_MODULE_INSTANCES=", tmp, NULL);
+ nvfree(tmp);
+
+ tmp = nvasprintf("Building %s kernel module:", module);
+ ui_status_begin(op, tmp, "Building");
+ nvfree(tmp);
+
+ cmd = nvstrcat("cd ", dir, "; make module",
+ " SYSSRC=", op->kernel_source_path,
+ " SYSOUT=", op->kernel_output_path,
+ instances, NULL);
+ nvfree(instances);
+
+ ret = run_command(op, cmd, NULL, TRUE, 25, TRUE);
+
+ nvfree(cmd);
+
+ if (ret != 0) {
+ ui_status_end(op, "Error.");
+ ui_error(op, "Unable to build the %s kernel module.", module);
+ /* XXX need more descriptive error message */
+ }
+
+ ui_status_end(op, "done.");
+
+ return ret == 0;
+}
+
+
+static int check_file(Options *op, Package *p, const char *filename,
+ const char *modname)
+{
+ int ret;
+ char *path;
+
+ path = nvstrcat(p->kernel_module_build_directory, "/", filename, NULL);
+ ret = access(path, F_OK);
+ nvfree(path);
+
+ if (ret == -1) {
+ ui_error(op, "The NVIDIA %s module was not created.", modname);
+ }
+
+ return ret != -1;
+}
+
+
/*
* build_kernel_module() - determine the kernel include directory,
* copy the kernel module source files into a temporary directory, and
@@ -556,7 +631,7 @@ int link_kernel_module(Options *op, Package *p, const char *build_directory,
int build_kernel_module(Options *op, Package *p)
{
- char *result, *cmd, *tmp;
+ char *result, *cmd;
int len, ret;
/*
@@ -583,63 +658,35 @@ int build_kernel_module(Options *op, Package *p)
if (!xen_check(op, p)) return FALSE;
if (!preempt_rt_check(op, p)) return FALSE;
- cmd = nvstrcat("cd ", p->kernel_module_build_directory,
- "; make print-module-filename",
- " SYSSRC=", op->kernel_source_path,
- " SYSOUT=", op->kernel_output_path, NULL);
-
- ret = run_command(op, cmd, &p->kernel_module_filename, FALSE, 0, FALSE);
-
- free(cmd);
-
- if (ret != 0) {
- ui_error(op, "Unable to determine the NVIDIA kernel module filename.");
- nvfree(result);
- return FALSE;
- }
-
ui_log(op, "Cleaning kernel module build directory.");
len = strlen(p->kernel_module_build_directory) + 32;
cmd = nvalloc(len);
-
+
snprintf(cmd, len, "cd %s; make clean", p->kernel_module_build_directory);
ret = run_command(op, cmd, &result, TRUE, 0, TRUE);
free(result);
free(cmd);
-
- ui_status_begin(op, "Building kernel module:", "Building");
-
- cmd = nvstrcat("cd ", p->kernel_module_build_directory,
- "; make module",
- " SYSSRC=", op->kernel_source_path,
- " SYSOUT=", op->kernel_output_path, NULL);
-
- ret = run_command(op, cmd, &result, TRUE, 25, TRUE);
- free(cmd);
+ ret = build_kernel_module_helper(op, p->kernel_module_build_directory,
+ "NVIDIA", op->num_kernel_modules);
- if (ret != 0) {
- ui_status_end(op, "Error.");
- ui_error(op, "Unable to build the NVIDIA kernel module.");
- /* XXX need more descriptive error message */
+ if (!ret) {
return FALSE;
}
- /* check that the file actually exists */
+ /* check that the frontend file actually exists */
+ if (op->multiple_kernel_modules) {
+ if (!check_file(op, p, p->kernel_frontend_module_filename, "frontend")) {
+ return FALSE;
+ }
+ }
- tmp = nvstrcat(p->kernel_module_build_directory, "/",
- p->kernel_module_filename, NULL);
- if (access(tmp, F_OK) == -1) {
- free(tmp);
- ui_status_end(op, "Error.");
- ui_error(op, "The NVIDIA kernel module was not created.");
+ /* check that the file actually exists */
+ if (!check_file(op, p, p->kernel_module_filename, "kernel")) {
return FALSE;
}
- free(tmp);
-
- ui_status_end(op, "done.");
ui_log(op, "Kernel module compilation complete.");
@@ -654,9 +701,11 @@ int build_kernel_module(Options *op, Package *p)
* for ensuring that the kernel module is already built successfully and that
* op->module_signing_{secret,public}_key are set.
*/
-int sign_kernel_module(Options *op, const char *build_directory, int status) {
+int sign_kernel_module(Options *op, const char *build_directory,
+ const char *module_suffix, int status) {
char *cmd, *mod_sign_cmd, *mod_sign_hash;
int ret, success;
+ char *build_module_instances_parameter;
/* if module_signing_script isn't set, then set mod_sign_cmd below to end
* the nvstrcat() that builds cmd early. */
@@ -673,11 +722,22 @@ int sign_kernel_module(Options *op, const char *build_directory, int status) {
ui_status_begin(op, "Signing kernel module:", "Signing");
}
+ if (op->multiple_kernel_modules) {
+ build_module_instances_parameter =
+ nvasprintf(" NV_BUILD_MODULE_INSTANCES=%d",
+ NV_MAX_MODULE_INSTANCES);
+ }
+ else {
+ build_module_instances_parameter = nvstrdup("");
+ }
+
cmd = nvstrcat("cd ", build_directory, "; make module-sign"
" SYSSRC=", op->kernel_source_path,
" SYSOUT=", op->kernel_output_path,
" MODSECKEY=", op->module_signing_secret_key,
" MODPUBKEY=", op->module_signing_public_key,
+ " NV_MODULE_SUFFIX=", module_suffix,
+ build_module_instances_parameter,
mod_sign_cmd ? mod_sign_cmd : "",
mod_sign_hash ? mod_sign_hash : "", NULL);
@@ -687,6 +747,7 @@ int sign_kernel_module(Options *op, const char *build_directory, int status) {
nvfree(mod_sign_hash);
nvfree(mod_sign_cmd);
nvfree(cmd);
+ nvfree(build_module_instances_parameter);
if (status) {
ui_status_end(op, success ? "done." : "Failed to sign kernel module.");
@@ -706,7 +767,9 @@ int sign_kernel_module(Options *op, const char *build_directory, int status) {
*/
static int create_detached_signature(Options *op, Package *p,
const char *build_dir,
- PrecompiledFileInfo *fileInfo)
+ PrecompiledFileInfo *fileInfo,
+ const char *module_suffix,
+ const char *module_filename)
{
int ret, command_ret;
struct stat st;
@@ -722,7 +785,7 @@ static int create_detached_signature(Options *op, Package *p,
goto done;
}
- module_path = nvstrcat(build_dir, "/", p->kernel_module_filename, NULL);
+ module_path = nvstrcat(build_dir, "/", module_filename, NULL);
command_ret = stat(module_path, &st);
if (command_ret != 0) {
@@ -738,7 +801,7 @@ static int create_detached_signature(Options *op, Package *p,
ui_status_update(op, .50, "Signing linked module");
- ret = sign_kernel_module(op, build_dir, FALSE);
+ ret = sign_kernel_module(op, build_dir, module_suffix, FALSE);
if (!ret) {
error = "Failed to sign the linked kernel module.";
@@ -763,7 +826,7 @@ done:
} else {
ui_status_end(op, "Error.");
if (error) {
- ui_error(op, error);
+ ui_error(op, "%s", error);
}
}
@@ -772,30 +835,115 @@ done:
} /* create_detached_signature() */
-
/*
- * build_kernel_interface() - build the kernel interface(s), and store any
- * built interfaces in a newly allocated PrecompiledFileInfo array, a pointer
- * to which is passed back to the caller. Return the number of packaged
- * interface files, or 0 on error.
+ * build_kernel_interface_file() - build the kernel interface(s).
+ * Returns true if the build was successful, or false on error.
*
* This is done by copying the sources to a temporary working
* directory and building the kernel interface in that directory.
- * The tmpdir is removed when complete.
+ */
+
+static int build_kernel_interface_file(Options *op, const char *tmpdir,
+ PrecompiledFileInfo *fileInfo,
+ const char *kernel_interface_filename,
+ const char *module_suffix,
+ const char *build_module_instances_parameter)
+{
+ char *cmd;
+ char *kernel_interface;
+ int command_ret;
+
+ cmd = nvstrcat("cd ", tmpdir, "; make ",
+ kernel_interface_filename,
+ " SYSSRC=", op->kernel_source_path,
+ " SYSOUT=", op->kernel_output_path,
+ " NV_MODULE_SUFFIX=", module_suffix,
+ build_module_instances_parameter, NULL);
+
+ command_ret = run_command(op, cmd, NULL, TRUE, 25 /* XXX */, TRUE);
+
+ free(cmd);
+
+ if (command_ret != 0) {
+ ui_status_end(op, "Error.");
+ ui_error(op, "Unable to build the NVIDIA kernel module interface.");
+ /* XXX need more descriptive error message */
+ return FALSE;
+ }
+
+ /* check that the file exists */
+
+ kernel_interface = nvstrcat(tmpdir, "/",
+ kernel_interface_filename, NULL);
+
+ if (access(kernel_interface, F_OK) == -1) {
+ ui_status_end(op, "Error.");
+ ui_error(op, "The NVIDIA kernel module interface was not created.");
+ nvfree(kernel_interface);
+ return FALSE;
+ }
+
+ nvfree(kernel_interface);
+ return TRUE;
+}
+
+/*
+ * pack_kernel_interface() - Store the input built interfaces in the
+ * PrecompiledFileInfo array.
+ *
+ * Returns true if the packing was successful, or false on error.
+ */
+
+static int pack_kernel_interface(Options *op, Package *p,
+ const char *build_dir,
+ PrecompiledFileInfo *fileInfo,
+ const char *module_suffix,
+ const char *kernel_interface,
+ const char *module_filename,
+ const char *core_file)
+{
+ int command_ret;
+
+ command_ret = precompiled_read_interface(fileInfo, kernel_interface,
+ module_filename,
+ core_file);
+
+ if (command_ret) {
+ if (op->module_signing_secret_key && op->module_signing_public_key) {
+ if (!create_detached_signature(op, p, build_dir, fileInfo,
+ module_suffix,
+ module_filename)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * build_kernel_interface() - build the kernel interface(s), and store any
+ * built interfaces in a newly allocated PrecompiledFileInfo array. Return
+ * the number of packaged interface files, or 0 on error.
+ *
+ * The tmpdir created to build the kernel interface is removed before exit.
+ *
+ * For multi-RM, the frontend module interface should be compiled and
+ * packaged too.
*
* XXX this and build_kernel_module() should be merged.
- * XXX for multi-RM the dispatch module should be compiled separately, then
- * packaged whole with file type PRECOMPILED_FILE_TYPE_MODULE.
*/
int build_kernel_interface(Options *op, Package *p,
PrecompiledFileInfo ** fileInfos)
{
char *tmpdir = NULL;
- char *cmd = NULL;
char *dstfile = NULL;
- int files_packaged = 0, command_ret, i;
- const int num_files = 1; /* XXX multi-RM */
+ int files_packaged = 0, i;
+ int num_files = 1;
+ int ret_status;
+ char *build_module_instances_parameter = NULL;
*fileInfos = NULL;
@@ -826,67 +974,113 @@ int build_kernel_interface(Options *op, Package *p,
touch_directory(op, p->kernel_module_build_directory);
- *fileInfos = nvalloc(sizeof(PrecompiledFileInfo) * num_files);
+ if (op->multiple_kernel_modules) {
+ num_files = op->num_kernel_modules;
+ build_module_instances_parameter =
+ nvasprintf(" NV_BUILD_MODULE_INSTANCES=%d",
+ NV_MAX_MODULE_INSTANCES);
+ }
+ else {
+ build_module_instances_parameter = nvstrdup("");
+ }
+
+ *fileInfos = nvalloc(sizeof(PrecompiledFileInfo) * (num_files + 1));
for (i = 0; i < num_files; i++) {
char *kernel_interface, *kernel_module_filename;
+ char *kernel_interface_filename;
PrecompiledFileInfo *fileInfo = *fileInfos + i;
+ char module_instance_str[5];
+
+ memset(module_instance_str, 0, sizeof(module_instance_str));
+ if (op->multiple_kernel_modules) {
+ snprintf(module_instance_str, sizeof(module_instance_str), "%d", i);
+ }
+
+ kernel_interface_filename = nvstrdup(p->kernel_interface_filename);
+
+ replace_zero(kernel_interface_filename, i);
/* build the kernel interface */
ui_status_begin(op, "Building kernel interface:", "Building (%d/%d)",
i + 1, num_files);
- cmd = nvstrcat("cd ", tmpdir, "; make ", p->kernel_interface_filename,
- " SYSSRC=", op->kernel_source_path, NULL);
-
- command_ret = run_command(op, cmd, NULL, TRUE, 25 /* XXX */, TRUE);
+ ret_status = build_kernel_interface_file(op, tmpdir, fileInfo,
+ kernel_interface_filename, module_instance_str,
+ build_module_instances_parameter);
- if (command_ret != 0) {
- ui_status_end(op, "Error.");
- ui_error(op, "Unable to build the NVIDIA kernel module interface.");
- /* XXX need more descriptive error message */
+ if (!ret_status) {
+ nvfree(kernel_interface_filename);
goto failed;
}
- /* check that the file exists */
+ ui_status_end(op, "done.");
+
+ ui_log(op, "Kernel module interface compilation complete.");
kernel_interface = nvstrcat(tmpdir, "/",
- p->kernel_interface_filename, NULL);
+ kernel_interface_filename, NULL);
+
+ kernel_module_filename = nvstrdup(p->kernel_module_filename);
- if (access(kernel_interface, F_OK) == -1) {
- ui_status_end(op, "Error.");
- ui_error(op, "The NVIDIA kernel module interface was not created.");
- nvfree(kernel_interface);
+ replace_zero(kernel_module_filename, i);
+
+ /* add the kernel interface to the list of files to be packaged */
+ ret_status = pack_kernel_interface(op, p, tmpdir, fileInfo,
+ module_instance_str,
+ kernel_interface,
+ kernel_module_filename,
+ "nv-kernel.o");
+
+ nvfree(kernel_interface);
+ nvfree(kernel_interface_filename);
+ nvfree(kernel_module_filename);
+
+ if (!ret_status)
+ goto failed;
+
+ files_packaged++;
+ }
+
+ if (op->multiple_kernel_modules) {
+ char *frontend_interface_filename;
+ PrecompiledFileInfo *fileInfo = *fileInfos + num_files;
+
+ ui_status_begin(op, "Building frontend interface: ", "Building");
+
+ ret_status = build_kernel_interface_file(op, tmpdir, fileInfo,
+ p->kernel_frontend_interface_filename, "frontend",
+ build_module_instances_parameter);
+
+ if (!ret_status)
goto failed;
- }
ui_status_end(op, "done.");
- ui_log(op, "Kernel module interface compilation complete.");
+ ui_log(op, "Frontend kernel module interface compilation complete.");
+
+ frontend_interface_filename = nvstrcat(tmpdir, "/",
+ p->kernel_frontend_interface_filename,
+ NULL);
/* add the kernel interface to the list of files to be packaged */
+ ret_status = pack_kernel_interface(op, p, tmpdir, fileInfo,
+ "frontend",
+ frontend_interface_filename,
+ p->kernel_frontend_module_filename,
+ "");
- kernel_module_filename = guess_kernel_module_filename(op);
- command_ret = precompiled_read_interface(fileInfo, kernel_interface,
- kernel_module_filename,
- "nv-kernel.o");
- nvfree(kernel_interface);
- nvfree(kernel_module_filename);
+ nvfree(frontend_interface_filename);
- if (command_ret) {
- if (op->module_signing_secret_key && op->module_signing_public_key) {
- if (!create_detached_signature(op, p, tmpdir, fileInfo)) {
- goto failed;
- }
- }
- files_packaged++;
- } else {
+ if (!ret_status)
goto failed;
- }
+
+ files_packaged++;
}
failed:
+ nvfree(build_module_instances_parameter);
if (files_packaged == 0) {
nvfree(*fileInfos);
@@ -897,7 +1091,7 @@ failed:
remove_directory(op, tmpdir);
nvfree(tmpdir);
}
- if (cmd) nvfree(cmd);
+
if (dstfile) nvfree(dstfile);
return files_packaged;
@@ -1072,6 +1266,118 @@ kmod_done:
} /* do_insmod() */
+/*
+ * Determine if the load error be ignored or not. Also print detailed
+ * error messages corresponding to the return status from do_install().
+ *
+ * Returns true if user chooses to ignore the load error, else, false.
+ */
+
+static int ignore_load_error(Options *op, Package *p,
+ const char *module_filename,
+ const char* data, int insmod_status)
+{
+ int ignore_error = FALSE, secureboot, module_sig_force, enokey;
+ const char *probable_reason, *signature_related;
+
+ enokey = (-insmod_status == ENOKEY);
+ secureboot = (secure_boot_enabled() == 1);
+ module_sig_force =
+ (test_kernel_config_option(op, p, "CONFIG_MODULE_SIG_FORCE") ==
+ KERNEL_CONFIG_OPTION_DEFINED);
+
+ if (enokey) {
+ probable_reason = ",";
+ signature_related = "";
+ } else if (module_sig_force) {
+ probable_reason = ". CONFIG_MODULE_SIG_FORCE is set on the target "
+ "kernel, so this is likely";
+ } else if (secureboot) {
+ probable_reason = ". Secure boot is enabled on this system, so "
+ "this is likely";
+ } else {
+ probable_reason = ", possibly";
+ }
+
+ if (!enokey) {
+ signature_related = "if this module loading failure is due to the "
+ "lack of a trusted signature, ";
+ }
+
+ if (enokey || secureboot || module_sig_force || op->expert) {
+ if (op->kernel_module_signed) {
+
+ ignore_error = ui_yes_no(op, TRUE,
+ "The signed kernel module failed to "
+ "load%s because the kernel does not "
+ "trust any key which is capable of "
+ "verifying the module signature. "
+ "Would you like to install the signed "
+ "kernel module anyway?\n\nNote that %s"
+ "you will not be able to load the "
+ "installed module until after a key "
+ "that can verify the module signature "
+ "is added to a key database that is "
+ "trusted by the kernel. This will "
+ "likely require rebooting your "
+ "computer.", probable_reason,
+ signature_related);
+ } else {
+ const char *secureboot_message, *dkms_message;
+
+ secureboot_message = secureboot == 1 ?
+ "and sign the kernel module when "
+ "prompted to do so." :
+ "and set the --module-signing-secret-"
+ "key and --module-signing-public-key "
+ "options on the command line, or run "
+ "the installer in expert mode to "
+ "enable the interactive module "
+ "signing prompts.";
+
+ dkms_message = op->dkms ? " Module signing is incompatible "
+ "with DKMS, so please select the "
+ "non-DKMS option when building the "
+ "kernel module to be signed." : "";
+ ui_error(op, "The kernel module failed to load%s because it "
+ "was not signed by a key that is trusted by the "
+ "kernel. Please try installing the driver again, %s%s",
+ probable_reason, secureboot_message, dkms_message);
+ }
+ }
+
+ if (ignore_error) {
+ ui_log(op, "An error was encountered when loading the kernel "
+ "module, but that error was ignored, and the kernel module "
+ "will be installed, anyway. The error was: %s", data);
+ } else {
+ ui_error(op, "Unable to load the kernel module '%s'. This "
+ "happens most frequently when this kernel module was "
+ "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, or nouveau is "
+ "present and prevents the NVIDIA kernel module from "
+ "obtaining ownership of the NVIDIA graphics device(s), "
+ "or no NVIDIA GPU installed in this system is supported "
+ "by this NVIDIA Linux graphics driver release.\n\n"
+ "Please see the log entries 'Kernel module load "
+ "error' and 'Kernel messages' at the end of the file "
+ "'%s' for more information.",
+ module_filename, op->log_file_name);
+
+ /*
+ * if in expert mode, run_command() would have caused this to
+ * be written to the log file; so if not in expert mode, print
+ * the output now.
+ */
+
+ if (!op->expert) ui_log(op, "Kernel module load error: %s", data);
+ }
+
+ return ignore_error;
+} /* ignore_load_error() */
+
/*
* test_kernel_module() - attempt to insmod the kernel module and then
@@ -1123,114 +1429,36 @@ int test_kernel_module(Options *op, Package *p)
nvfree(cmd);
}
- /* Load nvidia.ko */
+ if (op->multiple_kernel_modules) {
+ /* Load nvidia-frontend.ko */
+
+ module_path = nvstrcat(p->kernel_module_build_directory, "/",
+ p->kernel_frontend_module_filename, NULL);
+ ret = do_insmod(op, module_path, &data);
+ nvfree(module_path);
+
+ if (ret != 0) {
+ ret = ignore_load_error(op, p, p->kernel_frontend_module_filename,
+ data, ret);
+ goto test_exit;
+ }
+
+ nvfree(data);
+ }
+
+ /*
+ * Load nvidia0.ko while building multiple kernel modules or
+ * load nvidia.ko for non-multiple-kernel-module/simple builds.
+ */
+
module_path = nvstrcat(p->kernel_module_build_directory, "/",
p->kernel_module_filename, NULL);
ret = do_insmod(op, module_path, &data);
nvfree(module_path);
if (ret != 0) {
- int ignore_error = FALSE, secureboot, module_sig_force, enokey;
- const char *probable_reason, *signature_related;
-
- enokey = (-ret == ENOKEY);
- secureboot = (secure_boot_enabled() == 1);
- module_sig_force =
- (test_kernel_config_option(op, p, "CONFIG_MODULE_SIG_FORCE") ==
- KERNEL_CONFIG_OPTION_DEFINED);
-
- if (enokey) {
- probable_reason = ",";
- signature_related = "";
- } else if (module_sig_force) {
- probable_reason = ". CONFIG_MODULE_SIG_FORCE is set on the target "
- "kernel, so this is likely";
- } else if (secureboot) {
- probable_reason = ". Secure boot is enabled on this system, so "
- "this is likely";
- } else {
- probable_reason = ", possibly";
- }
-
- if (!enokey) {
- signature_related = "if this module loading failure is due to the "
- "lack of a trusted signature, ";
- }
-
- if (enokey || secureboot || module_sig_force || op->expert) {
- if (op->kernel_module_signed) {
-
- ignore_error = ui_yes_no(op, TRUE,
- "The signed kernel module failed to "
- "load%s because the kernel does not "
- "trust any key which is capable of "
- "verifying the module signature. "
- "Would you like to install the signed "
- "kernel module anyway?\n\nNote that %s"
- "you will not be able to load the "
- "installed module until after a key "
- "that can verify the module signature "
- "is added to a key database that is "
- "trusted by the kernel. This will "
- "likely require rebooting your "
- "computer.", probable_reason,
- signature_related);
- } else {
- const char *secureboot_message, *dkms_message;
-
- secureboot_message = secureboot == 1 ?
- "and sign the kernel module when "
- "prompted to do so." :
- "and set the --module-signing-secret-"
- "key and --module-signing-public-key "
- "options on the command line, or run "
- "the installer in expert mode to "
- "enable the interactive module "
- "signing prompts.";
-
- dkms_message = op->dkms ? " Module signing is incompatible "
- "with DKMS, so please select the "
- "non-DKMS option when building the "
- "kernel module to be signed." : "";
- ui_error(op, "The kernel module failed to load%s because it "
- "was not signed by a key that is trusted by the "
- "kernel. Please try installing the driver again, %s%s",
- probable_reason, secureboot_message, dkms_message);
- ignore_error = FALSE;
- }
- }
-
- if (ignore_error) {
- ui_log(op, "An error was encountered when loading the kernel "
- "module, but that error was ignored, and the kernel module "
- "will be installed, anyway. The error was: %s", data);
- ret = TRUE;
- } else {
- ui_error(op, "Unable to load the kernel module '%s'. This "
- "happens most frequently when this kernel module was "
- "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, or nouveau is "
- "present and prevents the NVIDIA kernel module from "
- "obtaining ownership of the NVIDIA graphics device(s), "
- "or no NVIDIA GPU installed in this system is supported "
- "by this NVIDIA Linux graphics driver release.\n\n"
- "Please see the log entries 'Kernel module load "
- "error' and 'Kernel messages' at the end of the file "
- "'%s' for more information.",
- p->kernel_module_filename, op->log_file_name);
-
- /*
- * if in expert mode, run_command() would have caused this to
- * be written to the log file; so if not in expert mode, print
- * the output now.
- */
-
- if (!op->expert) ui_log(op, "Kernel module load error: %s", data);
- ret = FALSE;
- }
-
+ ret = ignore_load_error(op, p, p->kernel_module_filename,
+ data, ret);
} else {
/*
@@ -1248,10 +1476,19 @@ int test_kernel_module(Options *op, Package *p)
*/
cmd = nvstrcat(op->utils[RMMOD], " ", p->kernel_module_name, NULL);
run_command(op, cmd, NULL, FALSE, 0, TRUE);
+
+ if (op->multiple_kernel_modules) {
+ nvfree(cmd);
+ cmd = nvstrcat(op->utils[RMMOD], " ",
+ p->kernel_frontend_module_name, NULL);
+ run_command(op, cmd, NULL, FALSE, 0, TRUE);
+ }
+
ret = TRUE;
nvfree(cmd);
}
+test_exit:
nvfree(data);
/*
@@ -1411,7 +1648,42 @@ int check_for_unloaded_kernel_module(Options *op, Package *p)
} /* check_for_unloaded_kernel_module() */
+/*
+ * add_file_to_search_filelist() - Add file to build a list
+ * of files expected to be unpacked.
+ */
+
+static void add_file_to_search_filelist(char **search_filelist, char *filename)
+{
+ int index = 0;
+
+ while(search_filelist[index]) {
+ index++;
+ }
+
+ if (index == SEARCH_FILELIST_MAX_ENTRIES)
+ return;
+
+ search_filelist[index] = nvstrdup(filename);
+} /* add_file_to_search_filelist() */
+
+
+/*
+ * free_search_filelist() - frees the list of files expected
+ * to unpack
+ */
+
+static void free_search_filelist(char **search_filelist)
+{
+ int index = 0;
+
+ while (search_filelist[index]) {
+ free(search_filelist[index]);
+ index++;
+ }
+
+} /*free_search_filelist() */
/*
@@ -1427,7 +1699,9 @@ PrecompiledInfo *find_precompiled_kernel_interface(Options *op, Package *p)
{
char *proc_version_string, *tmp;
PrecompiledInfo *info = NULL;
-
+ char *search_filelist[SEARCH_FILELIST_MAX_ENTRIES+1];
+ int index;
+
/* allow the user to completely skip this search */
if (op->no_precompiled_interface) {
@@ -1445,7 +1719,22 @@ PrecompiledInfo *find_precompiled_kernel_interface(Options *op, Package *p)
if (!mkdir_recursive(op, p->kernel_module_build_directory, 0755))
goto failed;
-
+
+ memset(search_filelist, 0, sizeof(search_filelist));
+
+ if (op->multiple_kernel_modules) {
+ add_file_to_search_filelist(search_filelist,
+ p->kernel_frontend_interface_filename);
+ }
+
+ for (index = 0; index < op->num_kernel_modules; index++) {
+ char *tmp;
+ tmp = nvstrdup(p->kernel_interface_filename);
+ replace_zero(tmp, index);
+ add_file_to_search_filelist(search_filelist, tmp);
+ free(tmp);
+ }
+
/*
* if the --precompiled-kernel-interfaces-path option was
* specified, search that directory, first
@@ -1453,7 +1742,7 @@ PrecompiledInfo *find_precompiled_kernel_interface(Options *op, Package *p)
if (op->precompiled_kernel_interfaces_path) {
info = scan_dir(op, p, op->precompiled_kernel_interfaces_path,
- proc_version_string);
+ proc_version_string, search_filelist);
}
/*
@@ -1464,11 +1753,11 @@ PrecompiledInfo *find_precompiled_kernel_interface(Options *op, Package *p)
if (!info) {
tmp = build_distro_precompiled_kernel_interface_dir(op);
if (tmp) {
- info = scan_dir(op, p, tmp, proc_version_string);
+ info = scan_dir(op, p, tmp, proc_version_string, search_filelist);
nvfree(tmp);
}
}
-
+
/*
* if we still haven't found a match, search in
* p->precompiled_kernel_interface_directory (the directory
@@ -1478,7 +1767,7 @@ PrecompiledInfo *find_precompiled_kernel_interface(Options *op, Package *p)
if (!info) {
info = scan_dir(op, p, p->precompiled_kernel_interface_directory,
- proc_version_string);
+ proc_version_string, search_filelist);
}
/*
@@ -1488,16 +1777,20 @@ PrecompiledInfo *find_precompiled_kernel_interface(Options *op, Package *p)
if (!info && !op->no_network && op->precompiled_kernel_interfaces_url) {
info = download_updated_kernel_interface(op, p,
- proc_version_string);
+ proc_version_string,
+ search_filelist);
if (!info) {
ui_message(op, "No matching precompiled kernel interface was "
"found at '%s'; this means that the installer will need "
"to compile a kernel interface for your kernel.",
op->precompiled_kernel_interfaces_url);
+ free_search_filelist(search_filelist);
return NULL;
}
}
+ free_search_filelist(search_filelist);
+
/* If we found one, ask expert users if they really want to use it */
if (info && op->expert) {
@@ -1893,7 +2186,8 @@ static int rmmod_kernel_module(Options *op, const char *module_name)
static PrecompiledInfo *
download_updated_kernel_interface(Options *op, Package *p,
- const char *proc_version_string)
+ const char *proc_version_string,
+ char *const *search_filelist)
{
int fd = -1;
int dst_fd = -1;
@@ -1999,7 +2293,7 @@ download_updated_kernel_interface(Options *op, Package *p,
/* XXX once we have gpg setup, should check the file here */
info = get_precompiled_info(op, dstfile, proc_version_string,
- p->version);
+ p->version, search_filelist);
if (!info) {
ui_error(op, "The format of the downloaded precompiled package "
@@ -2207,7 +2501,8 @@ static int preempt_rt_check(Options *op, Package *p)
static PrecompiledInfo *scan_dir(Options *op, Package *p,
const char *directory_name,
- const char *proc_version_string)
+ const char *proc_version_string,
+ char *const *search_filelist)
{
DIR *dir;
struct dirent *ent;
@@ -2232,7 +2527,7 @@ static PrecompiledInfo *scan_dir(Options *op, Package *p,
filename = nvstrcat(directory_name, "/", ent->d_name, NULL);
info = get_precompiled_info(op, filename, proc_version_string,
- p->version);
+ p->version, search_filelist);
free(filename);
@@ -2313,62 +2608,6 @@ static char *convert_include_path_to_source_path(const char *inc)
} /* convert_include_path_to_source_path() */
-
-/*
- * guess_kernel_module_filename() - parse uname to decide if the
- * kernel module filename is "nvidia.o" or "nvidia.ko".
- */
-
-static char *guess_kernel_module_filename(Options *op)
-{
- struct utsname uname_buf;
- char *tmp, *str, *dot0, *dot1;
- int major, minor;
-
- if (op->kernel_name) {
- str = op->kernel_name;
- } else {
- if (uname(&uname_buf) == -1) {
- ui_error (op, "Unable to determine kernel version (%s)",
- strerror (errno));
- return NULL;
- }
- str = uname_buf.release;
- }
-
- tmp = nvstrdup(str);
-
- dot0 = strchr(tmp, '.');
- if (!dot0) goto fail;
-
- *dot0 = '\0';
-
- major = atoi(tmp);
-
- dot0++;
- dot1 = strchr(dot0, '.');
- if (!dot1) goto fail;
-
- *dot1 = '\0';
-
- minor = atoi(dot0);
-
- if ((major > 2) || ((major == 2) && (minor > 4))) {
- return nvstrdup("nvidia.ko");
- } else {
- return nvstrdup("nvidia.o");
- }
-
- fail:
- ui_error (op, "Unable to determine if kernel is 2.6.0 or greater from "
- "uname string '%s'; assuming the kernel module filename is "
- "'nvidia.o'.", str);
- return nvstrdup("nvidia.o");
-
-} /* guess_kernel_module_filename() */
-
-
-
/*
* get_machine_arch() - get the machine architecture, substituting
* i386 for i586 and i686 or arm for arm7l.
diff --git a/kernel.h b/kernel.h
index a84be97..9bbc37c 100644
--- a/kernel.h
+++ b/kernel.h
@@ -46,9 +46,12 @@ PrecompiledInfo *find_precompiled_kernel_interface (Options*, Package*);
char *get_kernel_name (Options*);
KernelConfigOptionStatus test_kernel_config_option (Options*, Package*,
const char*);
-int sign_kernel_module (Options*, const char*, int);
+int sign_kernel_module (Options*, const char*,
+ const char*, int);
char *guess_module_signing_hash (Options*, Package*);
+#define SEARCH_FILELIST_MAX_ENTRIES 32
+
#ifndef ENOKEY
#define ENOKEY 126 /* Required key not available */
#endif
diff --git a/manifest.c b/manifest.c
index 86cf6d1..afce355 100644
--- a/manifest.c
+++ b/manifest.c
@@ -94,7 +94,9 @@ static const struct {
{ ENTRY(GLX_MODULE_SYMLINK, F, F, F, T, T, F, T ) },
{ ENTRY(XMODULE_NEWSYM, F, F, F, T, T, F, F ) },
{ ENTRY(VDPAU_LIB, T, F, T, T, F, T, F ) },
+ { ENTRY(VDPAU_WRAPPER_LIB, T, F, T, T, F, T, F ) },
{ ENTRY(VDPAU_SYMLINK, T, F, F, T, T, F, F ) },
+ { ENTRY(VDPAU_WRAPPER_SYMLINK, T, F, F, T, T, F, F ) },
{ ENTRY(NVCUVID_LIB, T, F, T, F, F, T, F ) },
{ ENTRY(NVCUVID_LIB_SYMLINK, T, F, F, F, T, F, F ) },
{ ENTRY(ENCODEAPI_LIB, T, F, T, F, F, T, F ) },
diff --git a/misc.c b/misc.c
index 6825fdc..597e27b 100644
--- a/misc.c
+++ b/misc.c
@@ -36,6 +36,9 @@
#include <dirent.h>
#include <libgen.h>
#include <pci/pci.h>
+#include <dlfcn.h>
+#include <elf.h>
+#include <link.h>
#ifndef PCI_CLASS_DISPLAY_3D
#define PCI_CLASS_DISPLAY_3D 0x302
@@ -448,8 +451,8 @@ int read_text_file(const char *filename, char **buf)
return FALSE;
while (((line = fget_next_line(fp, &eof)) != NULL)) {
- if ((index + strlen(line) + 1) > buflen) {
- buflen += 2 * strlen(line);
+ if ((index + strlen(line) + 2) > buflen) {
+ buflen = 2 * (index + strlen(line) + 2);
tmpbuf = (char *)nvalloc(buflen);
if (!tmpbuf) {
if (*buf) nvfree(*buf);
@@ -505,7 +508,7 @@ int find_system_utils(Options *op)
{ "tr", "coreutils" },
{ "sed", "sed" }
};
-
+
/* keep in sync with the SystemOptionalUtils enum type */
const struct { const char *util, *package; } optional_utils[] = {
{ "chcon", "selinux" },
@@ -534,22 +537,35 @@ int find_system_utils(Options *op)
needed_utils[i].package, needed_utils[i].util);
return FALSE;
}
-
+
ui_expert(op, "found `%s` : `%s`",
needed_utils[i].util, op->utils[i]);
}
-
+
for (j = 0, i = MAX_SYSTEM_UTILS; i < MAX_SYSTEM_OPTIONAL_UTILS; i++, j++) {
op->utils[i] = find_system_util(optional_utils[j].util);
if (op->utils[i]) {
ui_expert(op, "found `%s` : `%s`",
- optional_utils[j].util, op->utils[i]);
- } else {
- op->utils[i] = NULL;
+ optional_utils[j].util, op->utils[i]);
}
}
-
+
+ /* If no program called `X` is found; try searching for known X servers */
+ if (op->utils[XSERVER] == NULL) {
+ static const char* xservers[] = { "Xorg", "XFree86" };
+ int i;
+
+ for (i = 0; i < ARRAY_LEN(xservers); i++) {
+ op->utils[XSERVER] = find_system_util(xservers[i]);
+ if (op->utils[XSERVER]) {
+ ui_expert(op, "found `%s` : `%s`",
+ xservers[i], op->utils[XSERVER]);
+ break;
+ }
+ }
+ }
+
return TRUE;
} /* find_system_utils() */
@@ -1152,22 +1168,21 @@ void should_install_compat32_files(Options *op, Package *p)
* files are to be installed anyway.
*/
install_compat32_files = ui_yes_no(op, TRUE,
- "Install NVIDIA's 32-bit compatibility OpenGL "
- "libraries?");
+ "Install NVIDIA's 32-bit compatibility libraries?");
if (install_compat32_files && (op->compat32_chroot != NULL) &&
access(op->compat32_chroot, F_OK) < 0) {
install_compat32_files = ui_yes_no(op, FALSE,
- "The NVIDIA 32-bit compatibility OpenGL libraries are "
+ "The NVIDIA 32-bit compatibility libraries are "
"to be installed relative to the top-level prefix (chroot) "
"'%s'; however, this directory does not exist. Please "
"consult your distribution's documentation to confirm the "
"correct top-level installation prefix for 32-bit "
"compatiblity libraries.\n\nDo you wish to install the "
- "32-bit NVIDIA OpenGL compatibility libraries anyway?",
+ "NVIDIA 32-bit compatibility libraries anyway?",
op->compat32_chroot);
}
-
+
if (!install_compat32_files) {
for (i = 0; i < p->num_entries; i++) {
if (p->entries[i].compat_arch == FILE_COMPAT_ARCH_COMPAT32) {
@@ -1181,6 +1196,79 @@ void should_install_compat32_files(Options *op, Package *p)
/*
+ * detect_library() - attempt to dlopen(3) a DSO, to detect its availability.
+ */
+static int detect_library(const char *library)
+{
+ void *handle = dlopen(library, RTLD_NOW);
+
+ if (handle) {
+ dlclose(handle);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/*
+ * should_install_vdpau_wrapper() - ask the user if he/she wishes to
+ * install the VDPAU wrapper library.
+ */
+
+void should_install_vdpau_wrapper(Options *op, Package *p)
+{
+ /*
+ * If the user did not specifically request installation or non-installation
+ * of the VDPAU wrapper, default to installing only if the wrapper was not
+ * detected.
+ */
+ if (op->install_vdpau_wrapper == NV_OPTIONAL_BOOL_DEFAULT) {
+ if (detect_library("libvdpau.so.1")) {
+ op->install_vdpau_wrapper = NV_OPTIONAL_BOOL_FALSE;
+ } else {
+ op->install_vdpau_wrapper = NV_OPTIONAL_BOOL_TRUE;
+ }
+ }
+
+ /* give expert users an opportunity to override the default behavior and/or
+ * change their minds about any explicit command line setting */
+ if (op->expert) {
+ if (ui_yes_no(op, op->install_vdpau_wrapper,
+ "Install the libvdpau wrapper library?")) {
+ op->install_vdpau_wrapper = NV_OPTIONAL_BOOL_TRUE;
+ } else {
+ op->install_vdpau_wrapper = NV_OPTIONAL_BOOL_FALSE;
+ }
+ }
+
+ if (op->install_vdpau_wrapper == NV_OPTIONAL_BOOL_TRUE) {
+ ui_message(op, "nvidia-installer will install the libvdpau and "
+ "libvdpau_trace libraries that were included with this "
+ "installer package. These libraries are available "
+ "separately through the libvdpau project and will be "
+ "removed from the NVIDIA Linux driver installer package "
+ "in the future, so it is recommended that VDPAU users "
+ "install libvdpau separately, e.g. by using packages "
+ "available from their distributions, or by building "
+ "from the sources available at:\n\n"
+ "http://people.freedesktop.org/~aplattner/vdpau");
+ } else {
+ int i;
+
+ ui_log(op, "Skipping installation of the libvdpau wrapper library.");
+
+ for (i = 0; i < p->num_entries; i++) {
+ if (p->entries[i].type == FILE_TYPE_VDPAU_WRAPPER_LIB ||
+ p->entries[i].type == FILE_TYPE_VDPAU_WRAPPER_SYMLINK) {
+ invalidate_package_entry(&(p->entries[i]));
+ }
+ }
+ }
+}
+
+
+/*
* check_installed_files_from_package() - scan through the entries in
* the package, making sure that all symbolic links and files are
* properly installed.
@@ -1199,7 +1287,7 @@ void check_installed_files_from_package(Options *op, Package *p)
for (i = 0; i < p->num_entries; i++) {
percent = (float) i / (float) p->num_entries;
- ui_status_update(op, percent, p->entries[i].dst);
+ ui_status_update(op, percent, "%s", p->entries[i].dst);
if (p->entries[i].caps.is_symlink &&
/* Don't bother checking FILE_TYPE_NEWSYMs because we may not have
@@ -2459,8 +2547,10 @@ done:
static int prompt_for_user_cancel(Options *op, const char *file,
int default_cancel, const char *text)
{
- int ret, file_read;
- char *message = NULL;
+ int ret, file_read, msglen;
+ char *message = NULL, *prompt;
+
+ const char *buttons[2] = {"Continue Installation", "Cancel Installation"};
file_read = read_text_file(file, &message);
@@ -2468,12 +2558,21 @@ static int prompt_for_user_cancel(Options *op, const char *file,
message = nvstrdup("");
}
- ret = ui_yes_no(op, default_cancel,
- "%s\n\n%s\nWould you like to cancel this installation?",
- text, message);
+ msglen = strlen(message);
+
+ prompt = nvstrcat(text, msglen > 0 ? "\n\nPlease review the message "
+ "provided by the maintainer of this alternate "
+ "installation method and decide how to proceed:" : NULL,
+ NULL);
+
+ ret = ui_paged_prompt(op, prompt, msglen > 0 ? "Information about the "
+ "alternate information method" : "", message,
+ buttons, 2, default_cancel);
+
nvfree(message);
+ nvfree(prompt);
- return ret;
+ return ret == 1;
}
#define INSTALL_PRESENT_FILE "alternate-install-present"
@@ -2516,7 +2615,7 @@ int check_for_alternate_install(Options *op)
"uninstall the existing installation before installing this "
"driver.";
- return !prompt_for_user_cancel(op, alt_inst_present, TRUE, msg);
+ return !prompt_for_user_cancel(op, alt_inst_present, 1, msg);
}
if (access(alt_inst_avail, F_OK) == 0) {
@@ -2528,7 +2627,7 @@ int check_for_alternate_install(Options *op)
"better with your system than a driver installed by "
"nvidia-installer.";
- return !prompt_for_user_cancel(op, alt_inst_avail, FALSE, msg);
+ return !prompt_for_user_cancel(op, alt_inst_avail, 0, msg);
}
return TRUE;
@@ -2995,3 +3094,47 @@ int secure_boot_enabled(void) {
return ret;
}
+
+
+
+/*
+ * get_elf_architecture() - attempt to read an ELF header from the given file;
+ * returns ELF_ARCHITECTURE_{32,64,UNKNOWN} if the architecture could be parsed,
+ * ELF_INVALID_FILE on error, or if the file is not valid ELF.
+ */
+
+ElfFileType get_elf_architecture(const char *filename)
+{
+ FILE *fp;
+ ElfW(Ehdr) header;
+
+ fp = fopen(filename, "r");
+
+ /* Read the ELF header */
+
+ if (fp) {
+ int ret = fread(&header, sizeof(header), 1, fp);
+ fclose(fp);
+
+ if (ret != 1) {
+ return ELF_INVALID_FILE;
+ }
+ } else {
+ return ELF_INVALID_FILE;
+ }
+
+ /* Verify the magic number */
+
+ if (strncmp((char *) header.e_ident, "\177ELF", 4) != 0) {
+ return ELF_INVALID_FILE;
+ }
+
+ /* Parse the architecture from the ELF header */
+
+ switch(header.e_ident[EI_CLASS]) {
+ case ELFCLASS32: return ELF_ARCHITECTURE_32;
+ case ELFCLASS64: return ELF_ARCHITECTURE_64;
+ case ELFCLASSNONE: return ELF_ARCHITECTURE_UNKNOWN;
+ default: return ELF_INVALID_FILE;
+ }
+}
diff --git a/misc.h b/misc.h
index 8ea12e1..0cb0c79 100644
--- a/misc.h
+++ b/misc.h
@@ -30,6 +30,13 @@
#include "nvidia-installer.h"
#include "command-list.h"
+typedef enum {
+ ELF_INVALID_FILE,
+ ELF_ARCHITECTURE_UNKNOWN,
+ ELF_ARCHITECTURE_32,
+ ELF_ARCHITECTURE_64,
+} ElfFileType;
+
char *read_next_word (char *buf, char **e);
int check_euid(Options *op);
@@ -50,6 +57,7 @@ int continue_after_error(Options *op, const char *fmt, ...) NV_ATTRIBUTE_PRINTF(
int do_install(Options *op, Package *p, CommandList *c);
void should_install_opengl_headers(Options *op, Package *p);
void should_install_compat32_files(Options *op, Package *p);
+void should_install_vdpau_wrapper(Options *op, Package *p);
void check_installed_files_from_package(Options *op, Package *p);
int tls_test(Options *op, int compat_32_libs);
int check_runtime_configuration(Options *op, Package *p);
@@ -70,5 +78,6 @@ int unprelink(Options *op, const char *filename);
int verify_crc(Options *op, const char *filename, unsigned int crc,
unsigned int *actual_crc);
int secure_boot_enabled(void);
+ElfFileType get_elf_architecture(const char *filename);
#endif /* __NVIDIA_INSTALLER_MISC_H__ */
diff --git a/mkprecompiled.c b/mkprecompiled.c
index 3a4d3ca..f6ac578 100644
--- a/mkprecompiled.c
+++ b/mkprecompiled.c
@@ -522,7 +522,7 @@ static Options *parse_commandline(int argc, char *argv[])
break;
}
- op->package = get_precompiled_info(op, op->package_file, NULL, NULL);
+ op->package = get_precompiled_info(op, op->package_file, NULL, NULL, NULL);
if (!op->package && op->action != PACK) {
fprintf(stderr, "Unable to read package file '%s'.\n",
diff --git a/ncurses-ui.c b/ncurses-ui.c
index 7775fff..b0d6e04 100644
--- a/ncurses-ui.c
+++ b/ncurses-ui.c
@@ -186,8 +186,8 @@ static void nv_ncurses_destroy_region(RegionStruct *);
/* helper functions for drawing buttons */
-static void nv_ncurses_draw_button(DataStruct *, RegionStruct *,
- int, int, int, int, char *, bool, bool);
+static void nv_ncurses_draw_button(DataStruct *, RegionStruct *, int, int,
+ int, int, const char *, bool, bool);
static void nv_ncurses_erase_button(RegionStruct *, int, int, int, int);
@@ -206,6 +206,8 @@ static PagerStruct *nv_ncurses_create_pager(DataStruct *, int, int, int, int,
static void nv_ncurses_pager_update(DataStruct *, PagerStruct *);
static void nv_ncurses_pager_handle_events(DataStruct *, PagerStruct *, int);
static void nv_ncurses_destroy_pager(PagerStruct *);
+static int nv_ncurses_paged_prompt(Options *, const char*, const char*,
+ const char*, const char **, int, int);
/* progress bar helper functions */
@@ -217,11 +219,9 @@ static void init_position(int p[4], int w);
/* misc helper functions */
-static TextRows *nv_ncurses_create_command_list_textrows(DataStruct *,
- CommandList *, int);
+static char *nv_ncurses_create_command_list_text(DataStruct *, CommandList *);
static char *nv_ncurses_mode_to_permission_string(mode_t);
-static void nv_ncurses_concat_text_rows(TextRows *, TextRows *);
static void nv_ncurses_free_text_rows(TextRows *);
static int nv_ncurses_format_print(DataStruct *, RegionStruct *,
@@ -247,6 +247,7 @@ InstallerUI ui_dispatch_table = {
nv_ncurses_command_output,
nv_ncurses_approve_command_list,
nv_ncurses_yes_no,
+ nv_ncurses_paged_prompt,
nv_ncurses_status_begin,
nv_ncurses_status_update,
nv_ncurses_status_end,
@@ -621,140 +622,17 @@ static char *nv_ncurses_get_input(Options *op,
static int nv_ncurses_display_license(Options *op, const char *license)
{
- DataStruct *d = (DataStruct *) op->ui_priv;
- TextRows *t_pager = NULL;
- int ch, x, cur = 0;
- int button_width, button_y, accept_x, no_accept_x, accepted;
- PagerStruct *p = NULL;
- char *str;
-
static const char *descr = "Please read the following LICENSE "
"and then select either \"Accept\" to accept the license "
"and continue with the installation, or select "
"\"Do Not Accept\" to abort the installation.";
- nv_ncurses_check_resize(d, FALSE);
- accepted = FALSE;
-
- draw_license:
-
- /* free the pager, and pager's text rows */
-
- if (d->message) nv_ncurses_destroy_region(d->message);
- if (p) nv_ncurses_destroy_pager(p);
- if (t_pager) nv_ncurses_free_text_rows(t_pager);
-
- /* create the message region and print descr in it */
-
- nv_ncurses_do_message_region(d, NULL, descr, TRUE, 2);
-
- /* draw the accept buttons */
-
- button_width = 15;
- button_y = d->message->h - 2;
- accept_x = (d->message->w - (button_width * 3)) / 2;
- no_accept_x = accept_x + (button_width * 2);
-
- nv_ncurses_draw_button(d, d->message, accept_x, button_y, button_width,
- 1, "Accept", accepted, FALSE);
-
- nv_ncurses_draw_button(d, d->message, no_accept_x, button_y, button_width,
- 1, "Do Not Accept", !accepted, FALSE);
-
- /* init the pager to display the license */
-
- t_pager = d->format_text_rows(NULL, license, d->message->w, TRUE);
- p = nv_ncurses_create_pager(d, 1, d->message->h + 2, d->message->w,
- d->height - d->message->h - 4,
- t_pager, "NVIDIA Software License", cur);
- refresh();
-
- /* process key strokes */
-
- do {
- /* if a resize occurred, jump back to the top and redraw */
-
- if (nv_ncurses_check_resize(d, FALSE)) {
- cur = p->cur;
- goto draw_license;
- }
- ch = getch();
-
- switch (ch) {
- case NV_NCURSES_TAB:
- case KEY_LEFT:
- case KEY_RIGHT:
-
- /*
- * any of left, right, and tab will toggle which button is
- * selected
- */
-
- accepted ^= 1;
-
- nv_ncurses_draw_button(d, d->message, accept_x, button_y,
- button_width, 1, "Accept",
- accepted, FALSE);
-
- nv_ncurses_draw_button(d, d->message, no_accept_x, button_y,
- button_width, 1, "Do Not Accept",
- !accepted, FALSE);
- refresh();
- break;
-
- case NV_NCURSES_CTRL('L'):
- nv_ncurses_check_resize(d, TRUE);
- cur = p->cur;
- goto draw_license;
- break;
-
- default:
- break;
- }
-
- nv_ncurses_pager_handle_events(d, p, ch);
-
- } while (ch != NV_NCURSES_ENTER);
-
- /* animate the button being pushed down */
-
- x = accepted ? accept_x : no_accept_x;
- str = accepted ? "Accept" : "Do Not Accept";
-
- nv_ncurses_erase_button(d->message, x, button_y, button_width, 1);
- nv_ncurses_draw_button(d, d->message, x, button_y, button_width, 1,
- str, TRUE, TRUE);
- refresh();
- usleep(NV_NCURSES_BUTTON_PRESS_TIME);
-
- nv_ncurses_erase_button(d->message, x, button_y, button_width, 1);
- nv_ncurses_draw_button(d, d->message, x, button_y, button_width, 1,
- str, TRUE, FALSE);
- refresh();
- usleep(NV_NCURSES_BUTTON_PRESS_TIME);
-
- /* free the text rows used by the pager */
-
- nv_ncurses_free_text_rows(t_pager);
-
- /* free the pager */
-
- nv_ncurses_destroy_pager(p);
-
- /* restore the footer */
+ static const char *buttons[2] = {"Accept", "Do Not Accept"};
- nv_ncurses_set_footer(d, NV_NCURSES_DEFAULT_FOOTER_LEFT,
- NV_NCURSES_DEFAULT_FOOTER_RIGHT);
-
- /* free the message region */
-
- nv_ncurses_destroy_region(d->message);
- d->message = NULL;
-
- refresh();
+ int ret = nv_ncurses_paged_prompt(op, descr, "NVIDIA Software License",
+ license, buttons, 2, 1);
- return accepted;
-
+ return ret == 0;
} /* nv_ncurses_display_license() */
@@ -892,11 +770,9 @@ static int nv_ncurses_approve_command_list(Options *op, CommandList *cl,
const char *descr)
{
DataStruct *d = (DataStruct *) op->ui_priv;
- TextRows *t_pager = NULL;
- PagerStruct *p = NULL;
- char *str, *question;
- int button_w, button_y, yes_x, no_x;
- int len, ch, x, yes, cur = 0;
+ char *commandlist, *question;
+ int ret, len;
+ const char *buttons[2] = {"Yes", "No"};
/* initialize the question string */
@@ -905,131 +781,15 @@ static int nv_ncurses_approve_command_list(Options *op, CommandList *cl,
snprintf(question, len, "The following operations will be performed to "
"install the %s. Is this acceptable?", descr);
- /* check if the window was resized */
+ commandlist = nv_ncurses_create_command_list_text(d, cl);
- nv_ncurses_check_resize(d, FALSE);
- yes = 1;
-
- draw_command_list:
-
- /* free any existing message region, pager, and pager textrows */
-
- if (d->message) {
- nv_ncurses_destroy_region(d->message);
- d->message = NULL;
- }
- if (p) nv_ncurses_destroy_pager(p);
- if (t_pager) nv_ncurses_free_text_rows(t_pager);
-
- /* create the message region and print descr in it */
-
- nv_ncurses_do_message_region(d, NULL, question, TRUE, 2);
-
- /* draw the yes/no buttons */
-
- button_w = 7;
- button_y = d->message->h - 2;
- yes_x = (d->message->w - button_w*3)/2 + 0;
- no_x = (d->message->w - button_w*3)/2 + 2*button_w;
-
- nv_ncurses_draw_button(d, d->message, yes_x, button_y,
- button_w, 1, "Yes", yes, FALSE);
- nv_ncurses_draw_button(d, d->message, no_x, button_y,
- button_w, 1, "No", !yes, FALSE);
-
- /* draw the command list */
-
- t_pager = nv_ncurses_create_command_list_textrows(d, cl, d->message->w);
- p = nv_ncurses_create_pager(d, 1, d->message->h + 2, d->message->w,
- d->height - d->message->h - 4,
- t_pager, "Proposed Commandlist", cur);
- refresh();
-
- /* process key strokes */
-
- do {
- /* if a resize occurred, jump back to the top and redraw */
-
- if (nv_ncurses_check_resize(d, FALSE)) {
- cur = p->cur;
- goto draw_command_list;
- }
- ch = getch();
-
- switch (ch) {
- case NV_NCURSES_TAB:
- case KEY_LEFT:
- case KEY_RIGHT:
-
- /*
- * any of left, right, and tab will toggle which button is
- * selected
- */
-
- yes ^= 1;
-
- nv_ncurses_draw_button(d, d->message, yes_x, button_y,
- button_w, 1, "Yes", yes, FALSE);
- nv_ncurses_draw_button(d, d->message, no_x, button_y,
- button_w, 1, "No", !yes, FALSE);
- refresh();
- break;
-
- case NV_NCURSES_CTRL('L'):
- nv_ncurses_check_resize(d, TRUE);
- cur = p->cur;
- goto draw_command_list;
- break;
-
- default:
- break;
- }
-
- nv_ncurses_pager_handle_events(d, p, ch);
-
- } while (ch != NV_NCURSES_ENTER);
-
- /* animate the button being pushed down */
-
- x = yes ? yes_x : no_x;
- str = yes ? "Yes" : "No";
-
- nv_ncurses_erase_button(d->message, x, button_y, button_w, 1);
- nv_ncurses_draw_button(d, d->message, x, button_y,
- button_w, 1, str, TRUE, TRUE);
- refresh();
- usleep(NV_NCURSES_BUTTON_PRESS_TIME);
-
- nv_ncurses_erase_button(d->message, x, button_y, button_w, 1);
- nv_ncurses_draw_button(d, d->message, x, button_y,
- button_w, 1, str, TRUE, FALSE);
- refresh();
- usleep(NV_NCURSES_BUTTON_PRESS_TIME);
-
- /* free the text rows used by the pager */
-
- nv_ncurses_free_text_rows(t_pager);
-
- /* free the pager */
-
- nv_ncurses_destroy_pager(p);
-
- /* restore the footer */
-
- nv_ncurses_set_footer(d, NV_NCURSES_DEFAULT_FOOTER_LEFT,
- NV_NCURSES_DEFAULT_FOOTER_RIGHT);
-
- /* free the message region */
-
- nv_ncurses_destroy_region(d->message);
- d->message = NULL;
-
- refresh();
+ ret = nv_ncurses_paged_prompt(op, question, "Proposed CommandList",
+ commandlist, buttons, 2, 0);
free(question);
+ free(commandlist);
- return yes;
-
+ return ret == 0;
} /* nv_ncurses_approve_command_list() */
@@ -1552,7 +1312,7 @@ static void nv_ncurses_destroy_region(RegionStruct *region)
static void nv_ncurses_draw_button(DataStruct *d, RegionStruct *region,
int x, int y, int w, int h,
- char *str, bool hilite, bool down)
+ const char *str, bool hilite, bool down)
{
int i, j, n, attr = 0;
@@ -1906,6 +1666,161 @@ static void nv_ncurses_pager_handle_events(DataStruct *d,
}
} /* nv_ncurses_pager_handle_events() */
+static void draw_buttons(DataStruct *d, const char **buttons, int num_buttons,
+ int button, int button_w, const int *buttons_x,
+ int button_y)
+{
+ int i;
+
+ for (i = 0; i < num_buttons; i++) {
+ nv_ncurses_draw_button(d, d->message, buttons_x[i], button_y,
+ button_w, 1, buttons[i], button == i, FALSE);
+ }
+}
+
+/*
+ * nv_ncurses_paged_prompt() - display a question with multiple-choice buttons
+ * along with a scrollable paged text area, allowing the user to review the
+ * pageable text and select a button corresponding to the desired response.
+ * Returns the index of the button selected from the passed-in buttons array.
+ */
+
+static int nv_ncurses_paged_prompt(Options *op, const char *question,
+ const char *pager_title,
+ const char *pager_text, const char **buttons,
+ int num_buttons, int default_button)
+{
+ DataStruct *d = (DataStruct *) op->ui_priv;
+ TextRows *t_pager = NULL;
+ int ch, cur = 0;
+ int i, button_w = 0, button_y, button = default_button;
+ int buttons_x[num_buttons];
+ PagerStruct *p = NULL;
+
+ /* check if the window was resized */
+
+ nv_ncurses_check_resize(d, FALSE);
+
+ for (i = 0; i < num_buttons; i++) {
+ int len = strlen(buttons[i]);
+ if (len > button_w) {
+ button_w = len;
+ }
+ }
+ button_w += 4;
+
+ print_message:
+
+ /* free any existing message region, pager, and pager textrows */
+
+ if (d->message) {
+ nv_ncurses_destroy_region(d->message);
+ d->message = NULL;
+ }
+
+ if (p) {
+ nv_ncurses_destroy_pager(p);
+ p = NULL;
+ }
+ if (t_pager) {
+ nv_ncurses_free_text_rows(t_pager);
+ t_pager = NULL;
+ }
+
+ /* create the message region and print the question in it */
+
+ nv_ncurses_do_message_region(d, NULL, question, TRUE, 2);
+
+ button_y = d->message->h - 2;
+
+ for (i = 0; i < num_buttons; i++) {
+ buttons_x[i] = (i + 1) * (d->message->w / (num_buttons + 1)) -
+ button_w / 2;
+ }
+
+ draw_buttons(d, buttons, num_buttons, button, button_w, buttons_x,
+ button_y);
+
+ /* draw the paged text */
+
+ t_pager = d->format_text_rows(NULL, pager_text, d->message->w, TRUE);
+ p = nv_ncurses_create_pager(d, 1, d->message->h + 2, d->message->w,
+ d->height - d->message->h - 4, t_pager,
+ pager_title, cur);
+ refresh();
+
+ /* process key strokes */
+
+ do {
+ /* if a resize occurred, jump back to the top and redraw */
+ if (nv_ncurses_check_resize(d, FALSE)) {
+ cur = p->cur;
+ goto print_message;
+ }
+
+ ch = getch();
+
+ switch (ch) {
+ case NV_NCURSES_TAB:
+ case KEY_RIGHT:
+ button = (button + 1) % num_buttons;
+ draw_buttons(d, buttons, num_buttons, button, button_w,
+ buttons_x, button_y);
+ refresh();
+ break;
+
+ case KEY_LEFT:
+ button = (button + num_buttons - 1) % num_buttons;
+ draw_buttons(d, buttons, num_buttons, button, button_w,
+ buttons_x, button_y);
+ refresh();
+ break;
+
+ case NV_NCURSES_CTRL('L'):
+ nv_ncurses_check_resize(d, TRUE);
+ cur = p->cur;
+ goto print_message;
+ break;
+
+ default:
+ break;
+ }
+
+ nv_ncurses_pager_handle_events(d, p, ch);
+ } while (ch != NV_NCURSES_ENTER);
+
+ /* animate the button being pushed down */
+
+ nv_ncurses_erase_button(d->message, buttons_x[button], button_y,
+ button_w, 1);
+ nv_ncurses_draw_button(d, d->message, buttons_x[button], button_y,
+ button_w, 1, buttons[button], TRUE, TRUE);
+ refresh();
+ usleep(NV_NCURSES_BUTTON_PRESS_TIME);
+
+ nv_ncurses_erase_button(d->message, buttons_x[button], button_y,
+ button_w, 1);
+ nv_ncurses_draw_button(d, d->message, buttons_x[button], button_y,
+ button_w, 1, buttons[button], TRUE, FALSE);
+ refresh();
+ usleep(NV_NCURSES_BUTTON_PRESS_TIME);
+
+ /* restore the footer */
+
+ nv_ncurses_set_footer(d, NV_NCURSES_DEFAULT_FOOTER_LEFT,
+ NV_NCURSES_DEFAULT_FOOTER_RIGHT);
+
+ /* clean up */
+
+ nv_ncurses_free_text_rows(t_pager);
+ nv_ncurses_destroy_pager(p);
+ nv_ncurses_destroy_region(d->message);
+ d->message = NULL;
+
+ refresh();
+
+ return button;
+}
@@ -1962,20 +1877,14 @@ static void init_position(int p[4], int w)
/*
- * nv_ncurses_create_command_list_textrows() - build TextRows to
- * describe the command list
+ * nv_ncurses_create_command_list_text() - build a string from the command list
*/
-static TextRows *nv_ncurses_create_command_list_textrows(DataStruct *d,
- CommandList *cl,
- int w)
+static char *nv_ncurses_create_command_list_text(DataStruct *d, CommandList *cl)
{
int i, len;
Command *c;
- char *str, *perms;
- TextRows *t0, *t1;
-
- t0 = t1 = NULL;
+ char *str, *perms, *ret = strdup("");
for (i = 0; i < cl->num; i++) {
c = &cl->cmds[i];
@@ -2032,24 +1941,30 @@ static TextRows *nv_ncurses_create_command_list_textrows(DataStruct *d,
}
if (str) {
- t1 = d->format_text_rows(NV_BULLET_STR, str, w, TRUE);
-
- if (t0) {
- nv_ncurses_concat_text_rows(t0, t1);
- nv_ncurses_free_text_rows(t1);
- } else {
- t0 = t1;
- }
- t1 = NULL;
-
+ int lenret, lenstr;
+ char *tmp;
+
+ lenret = strlen(ret);
+ lenstr = strlen(str);
+ tmp = malloc(lenret + lenstr + 2 /* "\n\0" */);
+
+ tmp[0] = 0;
+
+ strncat(tmp, ret, lenret);
+ strncat(tmp, str, lenstr);
+
+ tmp[lenret + lenstr] = '\n';
+ tmp[lenret + lenstr + 1] = 0;
+
free(str);
+ free(ret);
+ ret = tmp;
}
}
- return t0;
-
-} /* nv_ncurses_create_command_list_textrows() */
+ return ret;
+}
/*
@@ -2080,27 +1995,6 @@ static char *nv_ncurses_mode_to_permission_string(mode_t mode)
} /* mode_to_permission_string() */
-/*
- * nv_ncurses_concat_text_rows() - concatenate two text rows
- */
-
-static void nv_ncurses_concat_text_rows(TextRows *t0, TextRows *t1)
-{
- int n, i;
-
- n = t0->n + t1->n;
-
- t0->t = (char **) realloc(t0->t, sizeof(char *) * n);
-
- for (i = 0; i < t1->n; i++) {
- t0->t[i + t0->n] = strdup(t1->t[i]);
- }
-
- t0->m = NV_MAX(t0->m, t1->m);
- t0->n = n;
-
-} /* nv_ncurses_concat_text_rows() */
-
/*
diff --git a/nvidia-installer-ui.h b/nvidia-installer-ui.h
index 1418a9c..e8f0c81 100644
--- a/nvidia-installer-ui.h
+++ b/nvidia-installer-ui.h
@@ -128,6 +128,20 @@ typedef struct __nv_installer_ui {
int (*yes_no)(Options *op, const int def, const char *msg);
/*
+ * paged_prompt - ask the question 'question' with 'num_answers' possible
+ * multiple choice answers in 'answers', with 'default_answer' as the
+ * default answer, and with scrollable 'pager_text' given as supplementary
+ * information, described by 'pager_title'. Returns the index into 'answers'
+ * of the user-selected answer to 'question'. The names of answers must
+ * not begin with digits, and the caller is responsible for enforcing this.
+ */
+
+ int (*paged_prompt)(Options *op, const char *question,
+ const char *pager_title, const char *pager_text,
+ const char **answers, int num_answers,
+ int default_answer);
+
+ /*
* status_begin(), status_update(), status_end() - these three
* functions display the status of some process. It is expected
* that status_begin() would be called, followed by some number of
diff --git a/nvidia-installer.c b/nvidia-installer.c
index cc3c752..3d8cb59 100644
--- a/nvidia-installer.c
+++ b/nvidia-installer.c
@@ -61,7 +61,7 @@ extern const char *pNV_ID;
static void print_version(void)
{
fmtout("");
- fmtout(pNV_ID);
+ fmtout("%s", pNV_ID);
fmtoutp(TAB, "The NVIDIA Software Installer for Unix/Linux.");
fmtout("");
fmtoutp(TAB, "This program is used to install, upgrade and uninstall "
@@ -79,8 +79,8 @@ static void print_version(void)
static void print_help_helper(const char *name, const char *description)
{
- fmtoutp(TAB, name);
- fmtoutp(BIGTAB, description);
+ fmtoutp(TAB, "%s", name);
+ fmtoutp(BIGTAB, "%s", description);
fmtout("");
}
@@ -146,7 +146,9 @@ static Options *load_default_options(void)
op->run_distro_scripts = TRUE;
op->no_kernel_module_source = FALSE;
op->dkms = FALSE;
+ op->install_vdpau_wrapper = NV_OPTIONAL_BOOL_DEFAULT;
op->check_for_alternate_installs = TRUE;
+ op->num_kernel_modules = 1;
return op;
@@ -170,6 +172,8 @@ static void parse_commandline(int argc, char *argv[], Options *op)
int print_help_args_only_after = FALSE;
int print_advanced_help = FALSE;
char *strval = NULL, *program_name = NULL;
+ int boolval;
+ int intval = 0;
/*
* if the installer was invoked as "nvidia-uninstall", perform an
@@ -183,9 +187,7 @@ static void parse_commandline(int argc, char *argv[], Options *op)
while (1) {
- c = nvgetopt(argc, argv, __options, &strval,
- NULL, /* boolval */
- NULL, /* intval */
+ c = nvgetopt(argc, argv, __options, &strval, &boolval, &intval,
NULL, /* doubleval */
NULL); /* disable_val */
@@ -406,6 +408,24 @@ static void parse_commandline(int argc, char *argv[], Options *op)
case MODULE_SIGNING_X509_HASH_OPTION:
op->module_signing_x509_hash = strval;
break;
+ case INSTALL_VDPAU_WRAPPER_OPTION:
+ op->install_vdpau_wrapper = boolval ? NV_OPTIONAL_BOOL_TRUE :
+ NV_OPTIONAL_BOOL_FALSE;
+ break;
+ case MULTIPLE_KERNEL_MODULES_OPTION:
+ if (intval < 0) {
+ fmterr("Invalid parameter for '--multiple-kernel-modules'");
+ goto fail;
+ }
+ op->multiple_kernel_modules = TRUE;
+ if (intval > NV_MAX_MODULE_INSTANCES)
+ op->num_kernel_modules = NV_MAX_MODULE_INSTANCES;
+ else
+ op->num_kernel_modules = intval;
+ break;
+ case NO_CHECK_FOR_ALTERNATE_INSTALLS_OPTION:
+ op->check_for_alternate_installs = FALSE;
+ break;
default:
goto fail;
}
diff --git a/nvidia-installer.h b/nvidia-installer.h
index 7f9effe..3389e10 100644
--- a/nvidia-installer.h
+++ b/nvidia-installer.h
@@ -146,6 +146,10 @@ typedef struct __options {
int no_kernel_module_source;
int dkms;
int check_for_alternate_installs;
+ int multiple_kernel_modules;
+ int num_kernel_modules;
+
+ NVOptionalBool install_vdpau_wrapper;
char *opengl_prefix;
char *opengl_libdir;
@@ -247,7 +251,9 @@ typedef enum {
FILE_TYPE_CUDA_LIB,
FILE_TYPE_CUDA_SYMLINK,
FILE_TYPE_VDPAU_LIB,
+ FILE_TYPE_VDPAU_WRAPPER_LIB,
FILE_TYPE_VDPAU_SYMLINK,
+ FILE_TYPE_VDPAU_WRAPPER_SYMLINK,
FILE_TYPE_UTILITY_BIN_SYMLINK,
FILE_TYPE_CUDA_ICD,
FILE_TYPE_NVCUVID_LIB,
@@ -358,6 +364,9 @@ typedef struct __package {
char **bad_module_filenames;
char *kernel_module_build_directory;
char *precompiled_kernel_interface_directory;
+ char *kernel_frontend_module_filename;
+ char *kernel_frontend_module_name;
+ char *kernel_frontend_interface_filename;
PackageEntry *entries; /* array of filename/checksum/bytesize entries */
int num_entries;
@@ -458,6 +467,8 @@ typedef struct __package {
#define NUM_TIMES_QUESTIONS_ASKED 3
+#define NV_MAX_MODULE_INSTANCES 8
+
#define LD_OPTIONS "-d -r"
#define NVIDIA_VERSION_PROC_FILE "/proc/driver/nvidia/version"
@@ -495,6 +506,7 @@ void add_package_entry(Package *p,
char *dst,
PackageEntryFileType type,
PackageEntryFileTlsClass tls_class,
+ PackageEntryFileCompatArch compat_arch,
mode_t mode);
/* XXX */
diff --git a/option_table.h b/option_table.h
index 897a054..4afb9bb 100644
--- a/option_table.h
+++ b/option_table.h
@@ -92,7 +92,9 @@ enum {
MODULE_SIGNING_KEY_PATH_OPTION,
MODULE_SIGNING_HASH_OPTION,
MODULE_SIGNING_X509_HASH_OPTION,
+ INSTALL_VDPAU_WRAPPER_OPTION,
NO_CHECK_FOR_ALTERNATE_INSTALLS_OPTION,
+ MULTIPLE_KERNEL_MODULES_OPTION,
};
static const NVGetoptOption __options[] = {
@@ -208,15 +210,15 @@ static const NVGetoptOption __options[] = {
{ "compat32-chroot", COMPAT32_CHROOT_OPTION, NVGETOPT_STRING_ARGUMENT,
NULL,
"The top-level prefix (chroot) relative to which the 32bit "
- "compatibility OpenGL libraries will be installed on Linux/x86-64 "
- "systems; this option is unset by default, the 32bit OpenGL "
+ "compatibility libraries will be installed on Linux/x86-64 "
+ "systems; this option is unset by default, the 32bit "
"library installation prefix (see below) and the 32bit library "
"path alone determine the target location. Only under very rare "
"circumstances should this option be used." },
{ "compat32-prefix", COMPAT32_PREFIX_OPTION, NVGETOPT_STRING_ARGUMENT,
NULL,
- "The prefix under which the 32bit compatibility OpenGL components "
+ "The prefix under which the 32bit compatibility components "
"of the NVIDIA driver will be installed; the default is: '"
DEFAULT_OPENGL_PREFIX "'. Only under rare circumstances should "
"this option be used." },
@@ -224,7 +226,7 @@ static const NVGetoptOption __options[] = {
{ "compat32-libdir", COMPAT32_LIBDIR_OPTION, NVGETOPT_STRING_ARGUMENT,
NULL,
"The path relative to the 32bit compatibility prefix under which the "
- "32bit compatibility OpenGL components of the NVIDIA driver will "
+ "32bit compatibility components of the NVIDIA driver will "
"be installed. The default is '" DEFAULT_LIBDIR "' or '"
UBUNTU_DEFAULT_COMPAT32_LIBDIR "', depending on the installed Linux "
"distribution. Only under very rare circumstances should this "
@@ -605,6 +607,16 @@ static const NVGetoptOption __options[] = {
"name must be one of the message digest algorithms recognized by "
"the x509(1) command." },
+ { "install-vdpau-wrapper", INSTALL_VDPAU_WRAPPER_OPTION,
+ NVGETOPT_IS_BOOLEAN, NULL,
+ "The NVIDIA driver package includes a VDPAU wrapper library for "
+ "convenience. By default, the wrapper library provided with the "
+ "driver package will not be installed if an existing wrapper "
+ "library is detected. Setting the '--install-vdpau-wrapper' option "
+ "will force the wrapper library to be installed; setting the "
+ "'--no-install-vdpau-wrapper' option will force the wrapper library to "
+ "be excluded from the installation." },
+
{ "no-check-for-alternate-installs", NO_CHECK_FOR_ALTERNATE_INSTALLS_OPTION,
0, NULL,
"Maintainers of alternate driver installation methods can report the "
@@ -612,6 +624,11 @@ static const NVGetoptOption __options[] = {
"nvidia-installer. Setting this option skips the check for alternate "
"driver installations." },
+ { "multiple-kernel-modules", MULTIPLE_KERNEL_MODULES_OPTION,
+ NVGETOPT_INTEGER_ARGUMENT, NULL,
+ "Build and install multiple NVIDIA kernel modules. The maximum number "
+ "of NVIDIA kernel modules that may be built is 8." },
+
/* 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/precompiled.c b/precompiled.c
index a5f8bfc..8d9e84e 100644
--- a/precompiled.c
+++ b/precompiled.c
@@ -148,7 +148,8 @@ char *read_proc_version(Options *op, const char *proc_mount_point)
PrecompiledInfo *get_precompiled_info(Options *op,
const char *filename,
const char *real_proc_version_string,
- const char *package_version)
+ const char *package_version,
+ char *const *search_filelist)
{
int fd, offset, num_files, i;
char *buf;
@@ -160,7 +161,7 @@ PrecompiledInfo *get_precompiled_info(Options *op,
fd = size = 0;
buf = description = proc_version_string = NULL;
-
+
/* open the file to be unpacked */
if ((fd = open(filename, O_RDONLY)) == -1) {
@@ -288,6 +289,35 @@ PrecompiledInfo *get_precompiled_info(Options *op,
}
}
+ /*
+ * Check for the package validity.
+ *
+ * The package is valid if all of the files specified in
+ * search_filelist are present in the package.
+ */
+
+ if (search_filelist != NULL) {
+ int index;
+
+ for (index = 0; search_filelist[index]; index++) {
+ int found = FALSE;
+
+ for (i = 0; i < num_files; i++) {
+ if (!strcmp(search_filelist[index], fileInfos[i].name)) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found) {
+ ui_log(op, "Required file '%s' not found in package '%s'",
+ search_filelist[index], filename);
+ goto done;
+ }
+ }
+ }
+
+
/*
* now that we can no longer fail, allocate and initialize the
* PrecompiledInfo structure
@@ -309,7 +339,7 @@ PrecompiledInfo *get_precompiled_info(Options *op,
proc_version_string = description = NULL;
fileInfos = NULL;
- done:
+done:
/* cleanup whatever needs cleaning up */
diff --git a/precompiled.h b/precompiled.h
index 7d727a6..ca33e20 100644
--- a/precompiled.h
+++ b/precompiled.h
@@ -163,7 +163,8 @@ char *read_proc_version(Options *op, const char *proc_mount_point);
PrecompiledInfo *get_precompiled_info(Options *op,
const char *filename,
const char *real_proc_version_string,
- const char *package_version);
+ const char *package_version,
+ char *const *search_filelist);
PrecompiledFileInfo *precompiled_find_file(const PrecompiledInfo *info,
const char *file);
diff --git a/stream-ui.c b/stream-ui.c
index be0326c..0b33199 100644
--- a/stream-ui.c
+++ b/stream-ui.c
@@ -45,6 +45,8 @@ void stream_message (Options*, int level, const char*);
void stream_command_output (Options*, const char*);
int stream_approve_command_list(Options*, CommandList*, const char*);
int stream_yes_no (Options*, const int, const char*);
+int stream_paged_prompt (Options *op, const char *, const char *,
+ const char *, const char **, int, int);
void stream_status_begin (Options*, const char*, const char*);
void stream_status_update (Options*, const float, const char*);
void stream_status_end (Options*, const char*);
@@ -60,6 +62,7 @@ InstallerUI stream_ui_dispatch_table = {
stream_command_output,
stream_approve_command_list,
stream_yes_no,
+ stream_paged_prompt,
stream_status_begin,
stream_status_update,
stream_status_end,
@@ -183,7 +186,7 @@ char *stream_get_input(Options *op, const char *def, const char *msg)
char *buf;
fmt(stdout, NULL, "");
- fmt(stdout, NULL, msg);
+ fmt(stdout, NULL, "%s", msg);
fprintf(stdout, " [default: '%s']: ", def);
fflush(stdout);
@@ -272,7 +275,7 @@ void stream_message(Options *op, const int level, const char *msg)
if ((level == NV_MSG_LEVEL_LOG) && (d->status_active)) return;
if (msg_attrs[level].newline) fmt(msg_attrs[level].stream, NULL, "");
- fmt(msg_attrs[level].stream, msg_attrs[level].prefix, msg);
+ fmt(msg_attrs[level].stream, msg_attrs[level].prefix, "%s", msg);
if (msg_attrs[level].newline) fmt(msg_attrs[level].stream, NULL, "");
} /* stream_message() */
@@ -292,7 +295,7 @@ void stream_command_output(Options *op, const char *msg)
if ((!op->expert) || (d->status_active)) return;
- fmtoutp(" ", msg);
+ fmtoutp(" ", "%s", msg);
} /* stream_command_output() */
@@ -384,7 +387,7 @@ int stream_yes_no(Options *op, const int def, const char *msg)
int eof, ret = def;
fmt(stdout, NULL, "");
- fmt(stdout, NULL, msg);
+ fmt(stdout, NULL, "%s", msg);
if (def) fprintf(stdout, " [default: (Y)es]: ");
else fprintf(stdout, " [default: (N)o]: ");
fflush(stdout);
@@ -405,6 +408,96 @@ int stream_yes_no(Options *op, const int def, const char *msg)
} /* stream_yes_no() */
+/*
+ * select_option - given a list of options and a user-provided selection, check
+ * to see if the selection matches any of the available options. Options can be
+ * selected either by index or by option name. Returns the caller-provided
+ * default option if the user's selection is an empty string, the index of the
+ * first (case-insensitive) matching option, or a negative number if no option
+ * matched the user's input.
+ */
+
+static int select_option(const char **options, int num_options,
+ int default_option, const char *selection)
+{
+ int i;
+
+ if (strlen(selection) == 0) {
+ return default_option;
+ }
+
+ if (isdigit(selection[0])) {
+ int index = atoi(selection);
+
+ if (index < 1 || index > num_options) {
+ return -2;
+ }
+
+ return index - 1;
+ }
+
+ for (i = 0; i < num_options; i++) {
+ if (strcasecmp(selection, options[i]) == 0) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+
+
+/*
+ * stream_paged_prompt() - display a question with multiple-choice answers
+ * along with a text area (not scrollable), allowing the user to review the text
+ * and select a button corresponding to the desired response. Returns the index
+ * answer selected from the passed-in answers array.
+ */
+
+int stream_paged_prompt(Options *op, const char *question,
+ const char *pager_title, const char *pager_text,
+ const char **answers, int num_answers,
+ int default_answer)
+{
+ int ret = default_answer;
+
+ fmtout("");
+ fmtout("________");
+ fmtout("");
+ fmtout("%s", pager_title);
+ fmtout("");
+ fmtout("%s", pager_text);
+ fmtout("");
+ fmtout("________");
+
+ do {
+ char *str;
+ int i;
+
+ if (ret < 0) {
+ fmterr("Invalid response!");
+ }
+
+ fmtout("");
+ fmtout("%s", question);
+ fmtout("Valid responses are: ");
+
+ for (i = 0; i < num_answers; i++) {
+ fmtout(" (%d)\t\"%s\"%s", i + 1, answers[i],
+ i == default_answer ? " [ default ]" : "");
+ }
+
+ fmtout("Please select your response by number or name:");
+ str = fget_next_line(stdin, NULL);
+
+ ret = select_option(answers, num_answers, default_answer, str);
+ free(str);
+ } while (ret < 0);
+
+ return ret;
+}
+
+
/*
* stream_status_begin() - we assume that title is always passed, but
@@ -417,7 +510,7 @@ void stream_status_begin(Options *op, const char *title, const char *msg)
d->status_active = TRUE;
- fmtout(title);
+ fmtout("%s", title);
d->status_label = nvstrdup(msg);
print_status_bar(d, STATUS_BEGIN, 0.0);
diff --git a/user-interface.c b/user-interface.c
index ea21045..6b655a0 100644
--- a/user-interface.c
+++ b/user-interface.c
@@ -214,7 +214,7 @@ char *ui_get_input(Options *op, const char *def, const char *fmt, ...)
ret = __ui->get_input(op, def, msg);
tmp = nvstrcat(msg, " (Answer: '", ret, "')", NULL);
}
- log_printf(op, NV_BULLET_STR, tmp);
+ log_printf(op, NV_BULLET_STR, "%s", tmp);
nvfree(msg);
nvfree(tmp);
@@ -249,7 +249,7 @@ void ui_error(Options *op, const char *fmt, ...)
NV_VSNPRINTF(msg, fmt);
__ui->message(op, NV_MSG_LEVEL_ERROR, msg);
- log_printf(op, "ERROR: ", msg);
+ log_printf(op, "ERROR: ", "%s", msg);
free(msg);
@@ -264,7 +264,7 @@ void ui_warn(Options *op, const char *fmt, ...)
NV_VSNPRINTF(msg, fmt);
__ui->message(op, NV_MSG_LEVEL_WARNING, msg);
- log_printf(op, "WARNING: ", msg);
+ log_printf(op, "WARNING: ", "%s", msg);
free(msg);
@@ -280,7 +280,7 @@ void ui_message(Options *op, const char *fmt, ...)
if (!op->silent) __ui->message(op, NV_MSG_LEVEL_MESSAGE, msg);
- log_printf(op, NV_BULLET_STR, msg);
+ log_printf(op, NV_BULLET_STR, "%s", msg);
free(msg);
@@ -294,7 +294,7 @@ void ui_log(Options *op, const char *fmt, ...)
NV_VSNPRINTF(msg, fmt);
if (!op->silent) __ui->message(op, NV_MSG_LEVEL_LOG, msg);
- log_printf(op, NV_BULLET_STR, msg);
+ log_printf(op, NV_BULLET_STR, "%s", msg);
free(msg);
@@ -315,7 +315,7 @@ void ui_expert(Options *op, const char *fmt, ...)
NV_VSNPRINTF(msg, fmt);
if (!op->silent) __ui->message(op, NV_MSG_LEVEL_LOG, msg);
- log_printf(op, NV_BULLET_STR, msg);
+ log_printf(op, NV_BULLET_STR, "%s", msg);
free (msg);
@@ -385,7 +385,7 @@ int ui_yes_no (Options *op, const int def, const char *fmt, ...)
tmp = nvstrcat(msg, " (Answer: ", (ret ? "Yes" : "No"), ")", NULL);
}
- log_printf(op, NV_BULLET_STR, tmp);
+ log_printf(op, NV_BULLET_STR, "%s", tmp);
nvfree(msg);
nvfree(tmp);
@@ -394,12 +394,38 @@ int ui_yes_no (Options *op, const int def, const char *fmt, ...)
} /* ui_yes_no() */
+int ui_paged_prompt (Options *op, const char *question, const char *pager_title,
+ const char *pager_text, const char **answers,
+ int num_answers, int default_answer)
+{
+ char *tmp;
+ int ret;
+
+ if (op->no_questions) {
+ ret = default_answer;
+ } else {
+ ret = __ui->paged_prompt(op, question, pager_title, pager_text, answers,
+ num_answers, default_answer);
+ }
+
+ tmp = nvstrcat("(Answer: ", answers[ret], ")", NULL);
+
+ if (!op->silent) {
+ __ui->message(op, NV_MSG_LEVEL_LOG, tmp);
+ }
+
+ log_printf(op, NV_BULLET_STR, "%s", tmp);
+ nvfree(tmp);
+
+ return ret;
+}
+
void ui_status_begin(Options *op, const char *title, const char *fmt, ...)
{
char *msg;
- log_printf(op, NV_BULLET_STR, title);
+ log_printf(op, NV_BULLET_STR, "%s", title);
if (op->silent) return;
@@ -432,7 +458,7 @@ void ui_status_end(Options *op, const char *fmt, ...)
NV_VSNPRINTF(msg, fmt);
if (!op->silent) __ui->status_end(op, msg);
- log_printf(op, NV_BULLET_STR, msg);
+ log_printf(op, NV_BULLET_STR, "%s", msg);
free(msg);
}
diff --git a/user-interface.h b/user-interface.h
index bcf5dbb..ac216c3 100644
--- a/user-interface.h
+++ b/user-interface.h
@@ -38,6 +38,8 @@ void ui_expert (Options*, const char*, ...) NV_ATTRIB
void ui_command_output (Options*, const char*, ...) NV_ATTRIBUTE_PRINTF(2, 3);
int ui_approve_command_list(Options*, CommandList*,const char*, ...) NV_ATTRIBUTE_PRINTF(3, 4);
int ui_yes_no (Options*, const int, const char*, ...) NV_ATTRIBUTE_PRINTF(3, 4);
+int ui_paged_prompt (Options *, const char *, const char *,
+ const char *, const char **, int, int);
void ui_status_begin (Options*, const char*, const char*, ...) NV_ATTRIBUTE_PRINTF(3, 4);
void ui_status_update (Options*, const float, const char*, ...) NV_ATTRIBUTE_PRINTF(3, 4);
void ui_status_end (Options*, const char*, ...) NV_ATTRIBUTE_PRINTF(2, 3);
diff --git a/utils.mk b/utils.mk
index 54b76d6..ce645c7 100644
--- a/utils.mk
+++ b/utils.mk
@@ -31,7 +31,7 @@ LD ?= ld
# only set these warnings and optimizations if CFLAGS is unset
CFLAGS ?= -Wall -O2
# always set these -f CFLAGS
-CFLAGS += -fno-strict-aliasing -fno-omit-frame-pointer
+CFLAGS += -fno-strict-aliasing -fno-omit-frame-pointer -Wformat=2
CC_ONLY_CFLAGS ?=
LDFLAGS ?=
BIN_LDFLAGS ?=
diff --git a/version.mk b/version.mk
index 8a89afe..2abb57a 100644
--- a/version.mk
+++ b/version.mk
@@ -1 +1 @@
-NVIDIA_VERSION = 325.15
+NVIDIA_VERSION = 331.13