summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Plattner <aplattner@nvidia.com>2013-07-01 08:54:54 -0700
committerAaron Plattner <aplattner@nvidia.com>2013-07-01 08:54:54 -0700
commitbae15338d0f3be4553a09bb6d9dd3c702a83c457 (patch)
tree02d30b43bf1bc2fa9d97cc5a3aa9869c5012ccfe
parent45f2c99ed857988e274557857edbf494702e037e (diff)
325.08325.08
-rw-r--r--Makefile3
-rw-r--r--command-list.c1
-rw-r--r--common-utils/common-utils.c114
-rw-r--r--common-utils/common-utils.h45
-rw-r--r--crc.c30
-rw-r--r--crc.h1
-rw-r--r--files.c93
-rw-r--r--files.h4
-rw-r--r--install-from-cwd.c34
-rw-r--r--kernel.c523
-rw-r--r--kernel.h7
-rw-r--r--misc.c98
-rw-r--r--misc.h1
-rw-r--r--mkprecompiled.c997
-rw-r--r--nvidia-installer.1.m410
-rw-r--r--nvidia-installer.c1
-rw-r--r--nvidia-installer.h6
-rw-r--r--option_table.h8
-rw-r--r--precompiled.c826
-rw-r--r--precompiled.h169
-rw-r--r--version.mk2
21 files changed, 1962 insertions, 1011 deletions
diff --git a/Makefile b/Makefile
index d69eec9..dd2da20 100644
--- a/Makefile
+++ b/Makefile
@@ -151,7 +151,8 @@ HOST_CFLAGS += $(common_cflags)
LDFLAGS += -L.
LIBS += -ldl
-MKPRECOMPILED_SRC = crc.c mkprecompiled.c
+MKPRECOMPILED_SRC = crc.c mkprecompiled.c $(COMMON_UTILS_DIR)/common-utils.c \
+ precompiled.c $(COMMON_UTILS_DIR)/nvgetopt.c
MKPRECOMPILED_OBJS = $(call BUILD_OBJECT_LIST,$(MKPRECOMPILED_SRC))
MAKESELF_HELP_SCRIPT_SRC = makeself-help-script.c
diff --git a/command-list.c b/command-list.c
index 48506d0..bfa22dc 100644
--- a/command-list.c
+++ b/command-list.c
@@ -599,6 +599,7 @@ static ConflictingFileInfo __xfree86_non_opengl_libs[] = {
{ "libnvidia-ml.", 13, /* strlen("libnvidia-ml.") */ NULL },
{ "libnvidia-encode.", 17, /* strlen("libnvidia-encode.") */ NULL },
{ "libnvidia-vgx.", 14, /* strlen("libnvidia-vgx.") */ NULL },
+ { "libnvidia-vgxcfg.", 17, /* strlen("libnvidia-vgxcfg.") */ NULL },
{ NULL, 0, NULL }
};
diff --git a/common-utils/common-utils.c b/common-utils/common-utils.c
index 9b734f3..b2958a7 100644
--- a/common-utils/common-utils.c
+++ b/common-utils/common-utils.c
@@ -492,8 +492,6 @@ void nv_text_rows_append(TextRows *t, const char *msg)
* result in t0
*/
-#define NV_MAX(x,y) ((x) > (y) ? (x) : (y))
-
void nv_concat_text_rows(TextRows *t0, TextRows *t1)
{
int n, i;
@@ -707,6 +705,107 @@ char *nvstrchrnul(char *s, int c)
return result;
}
+/****************************************************************************/
+/* file helper functions */
+/****************************************************************************/
+
+/*
+ * nv_open() - open(2) wrapper; prints an error message if open(2)
+ * fails and calls exit(). This function only returns on success.
+ */
+
+int nv_open(const char *pathname, int flags, mode_t mode)
+{
+ int fd;
+ fd = open(pathname, flags, mode);
+ if (fd == -1) {
+ fprintf(stderr, "Failure opening %s (%s).\n",
+ pathname, strerror(errno));
+ exit(1);
+ }
+ return fd;
+
+} /* nv_name() */
+
+
+
+/*
+ * nv_get_file_length() - stat(2) wrapper; prints an error message if
+ * the system call fails and calls exit(). This function only returns
+ * on success.
+ */
+
+int nv_get_file_length(const char *filename)
+{
+ struct stat stat_buf;
+ int ret;
+
+ ret = stat(filename, &stat_buf);
+ if (ret == -1) {
+ fprintf(stderr, "Unable to determine '%s' file length (%s).\n",
+ filename, strerror(errno));
+ exit(1);
+ }
+ return stat_buf.st_size;
+
+} /* nv_get_file_length() */
+
+
+
+/*
+ * nv_set_file_length() - wrapper for lseek() and write(); prints an
+ * error message if the system calls fail and calls exit(). This
+ * function only returns on success.
+ */
+
+void nv_set_file_length(const char *filename, int fd, int len)
+{
+ if ((lseek(fd, len - 1, SEEK_SET) == -1) ||
+ (write(fd, "", 1) == -1)) {
+ fprintf(stderr, "Unable to set file '%s' length %d (%s).\n",
+ filename, fd, strerror(errno));
+ exit(1);
+ }
+} /* nv_set_file_length() */
+
+
+
+/*
+ * nv_mmap() - mmap(2) wrapper; prints an error message if mmap(2)
+ * fails and calls exit(). This function only returns on success.
+ */
+
+void *nv_mmap(const char *filename, size_t len, int prot, int flags, int fd)
+{
+ void *ret;
+
+ ret = mmap(0, len, prot, flags, fd, 0);
+ if (ret == (void *) -1) {
+ fprintf(stderr, "Unable to mmap file %s (%s).\n",
+ filename, strerror(errno));
+ exit(1);
+ }
+ return ret;
+
+} /* nv_mmap() */
+
+
+/*
+ * nv_basename() - alternative to basename(3) which avoids differences in
+ * behavior from different implementations: this implementation never modifies
+ * the original string, and the return value can always be passed to free(3).
+ */
+
+char *nv_basename(const char *path)
+{
+ char *last_slash = strrchr(path, '/');
+ if (last_slash) {
+ return strdup(last_slash+1);
+ } else {
+ return strdup(path);
+ }
+}
+
/****************************************************************************/
/* string helper functions */
@@ -741,8 +840,12 @@ char *nv_trim_space(char *string) {
static char *trim_char(char *string, char trim, int *count) {
int len, replaced = 0;
- if (!string || trim == '\0') {
- return NULL;
+ if (count) {
+ *count = 0;
+ }
+
+ if (string == NULL || trim == '\0') {
+ return string;
}
if (string[0] == trim) {
@@ -781,7 +884,7 @@ char *nv_trim_char(char *string, char trim) {
*/
char *nv_trim_char_strict(char *string, char trim) {
- int count = 0;
+ int count;
char *trimmed;
trimmed = trim_char(string, trim, &count);
@@ -792,3 +895,4 @@ char *nv_trim_char_strict(char *string, char trim) {
return NULL;
}
+
diff --git a/common-utils/common-utils.h b/common-utils/common-utils.h
index 6dced25..92c57dd 100644
--- a/common-utils/common-utils.h
+++ b/common-utils/common-utils.h
@@ -19,6 +19,8 @@
#include <stdio.h>
#include <stdarg.h>
+#include <sys/types.h>
+#include <stdint.h>
#if !defined(TRUE)
#define TRUE 1
@@ -30,6 +32,9 @@
#define ARRAY_LEN(_arr) (sizeof(_arr) / sizeof(_arr[0]))
+#define NV_MIN(x,y) ((x) < (y) ? (x) : (y))
+#define NV_MAX(x,y) ((x) > (y) ? (x) : (y))
+
#define TAB " "
#define BIGTAB " "
@@ -90,6 +95,12 @@ void fmt(FILE *stream, const char *prefix, const char *fmt, ...) NV_ATTRIBUTE_PR
char *fget_next_line(FILE *fp, int *eof);
+int nv_open(const char *pathname, int flags, mode_t mode);
+int nv_get_file_length(const char *filename);
+void nv_set_file_length(const char *filename, int fd, int len);
+void *nv_mmap(const char *filename, size_t len, int prot, int flags, int fd);
+char *nv_basename(const char *path);
+
char *nv_trim_space(char *string);
char *nv_trim_char(char *string, char trim);
char *nv_trim_char_strict(char *string, char trim);
@@ -139,4 +150,38 @@ do { \
} \
} while (0)
+#if defined(__GNUC__)
+# define NV_INLINE __inline__
+#else
+# define NV_INLINE
+#endif
+
+/*
+ * Simple function which encodes a version number, given as major, minor, micro,
+ * and nano, as a 64-bit unsigned integer. This is defined in an inline function
+ * rather than as a macro for convenience so it can be examined by the debugger.
+ * Encoded version numbers can be compared directly in version checks.
+ */
+static NV_INLINE uint64_t nv_encode_version(unsigned int major,
+ unsigned int minor,
+ unsigned int micro,
+ unsigned int nano)
+{
+ return (((uint64_t)(nano & 0xFFFF)) |
+ (((uint64_t)(micro & 0xFFFF)) << 16) |
+ (((uint64_t)(minor & 0xFFFF)) << 32) |
+ (((uint64_t)(major & 0xFFFF)) << 48));
+}
+
+/*
+ * Wrapper macros for nv_encode_version(). For K in {2,3,4}, NV_VERSIONK() takes
+ * a K-part version number.
+ */
+#define NV_VERSION2(major, minor) \
+ nv_encode_version(major, minor, 0, 0)
+#define NV_VERSION3(major, minor, micro) \
+ nv_encode_version(major, minor, micro, 0)
+#define NV_VERSION4(major, minor, micro, nano) \
+ nv_encode_version(major, minor, micro, nano)
+
#endif /* __COMMON_UTILS_H__ */
diff --git a/crc.c b/crc.c
index 9149e73..e3e63bb 100644
--- a/crc.c
+++ b/crc.c
@@ -69,15 +69,12 @@ static uint32 crc_init(uint32 crc)
-uint32 compute_crc(Options *op, const char *filename)
+uint32 compute_crc_from_buffer(const uint8 *buf, int len)
{
uint32 cword = ~0;
static uint32 *crctab = NULL;
- uint8 *buf;
- int i, fd;
- struct stat stat_buf;
- size_t len;
-
+ int i;
+
if (!crctab) {
crctab = (uint32 *) nvalloc(sizeof(uint32) * 256);
for (i=0; i < 256; i++) {
@@ -85,6 +82,23 @@ uint32 compute_crc(Options *op, const char *filename)
}
}
+ for (i = 0; i < len; i++) {
+ cword = crctab[buf[i] ^ (cword >> 24)] ^ (cword << 8);
+ }
+
+ return cword;
+}
+
+
+
+uint32 compute_crc(Options *op, const char *filename)
+{
+ uint32 cword = ~0;
+ uint8 *buf;
+ int fd;
+ struct stat stat_buf;
+ size_t len;
+
if ((fd = open(filename, O_RDONLY)) == -1) goto fail;
if (fstat(fd, &stat_buf) == -1) goto fail;
@@ -94,9 +108,7 @@ uint32 compute_crc(Options *op, const char *filename)
buf = mmap(0, len, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0);
if (buf == (void *) -1) goto fail;
- for (i = 0; i < len; i++) {
- cword = crctab[buf[i] ^ (cword >> 24)] ^ (cword << 8);
- }
+ cword = compute_crc_from_buffer(buf, len);
if (munmap(buf, len) == -1) goto fail;
if (close(fd) == -1) goto fail;
diff --git a/crc.h b/crc.h
index 2f0a5f3..3f5b373 100644
--- a/crc.h
+++ b/crc.h
@@ -21,6 +21,7 @@
#ifndef __NVIDIA_INSTALLER_CRC_H__
#define __NVIDIA_INSTALLER_CRC_H__
+uint32 compute_crc_from_buffer(const uint8 *buf, int len);
uint32 compute_crc(Options *op, const char *filename);
#endif /* __NVIDIA_INSTALLER_CRC_H__ */
diff --git a/files.c b/files.c
index 692096f..f84716d 100644
--- a/files.c
+++ b/files.c
@@ -1592,16 +1592,19 @@ int copy_directory_contents(Options *op, const char *src, const char *dst)
/*
- * pack_precompiled_kernel_interface() -
+ * pack_precompiled_files() - Create a new precompiled files package for the
+ * given PrecompiledFileInfo array and save it to disk.
*/
-int pack_precompiled_kernel_interface(Options *op, Package *p)
+int pack_precompiled_files(Options *op, Package *p, int num_files,
+ PrecompiledFileInfo *files)
{
- char *cmd, time_str[256], *proc_version_string, *suffix, *file, *newfile;
- char *result, *descr;
+ char time_str[256], *proc_version_string;
+ char *outfile, *descr;
time_t t;
struct utsname buf;
int ret;
+ PrecompiledInfo *info;
ui_log(op, "Packaging precompiled kernel interface.");
@@ -1616,7 +1619,7 @@ int pack_precompiled_kernel_interface(Options *op, Package *p)
/* read the proc version string */
- proc_version_string = read_proc_version(op);
+ proc_version_string = read_proc_version(op, op->proc_mount_point);
/* use the uname string as the description */
@@ -1625,74 +1628,36 @@ int pack_precompiled_kernel_interface(Options *op, Package *p)
buf.release, " ",
buf.version, " ",
buf.machine, NULL);
-
- /* build the mkprecompiled command */
-
- suffix = nvstrcat("-", p->version, ".", time_str, NULL);
-
- cmd = nvstrcat("./mkprecompiled --interface=",
- p->kernel_module_build_directory, "/",
- PRECOMPILED_KERNEL_INTERFACE_FILENAME,
- " --output=", p->precompiled_kernel_interface_directory,
- "/", PRECOMPILED_KERNEL_INTERFACE_FILENAME, suffix,
- " --description=\"", descr, "\"",
- " --proc-version=\"", proc_version_string, "\"",
- " --version=", p->version, NULL);
-
- /* execute the command */
-
- ret = run_command(op, cmd, &result, FALSE, 0, TRUE);
-
- nvfree(cmd);
- nvfree(proc_version_string);
- nvfree(descr);
- /* pack the detached signature and checksum, if they exist */
+ /* build the PrecompiledInfo struct */
- file = nvstrcat(p->kernel_module_build_directory, "/",
- DETACHED_SIGNATURE_FILENAME, NULL);
-
- if (access(file, R_OK) == 0) {
- newfile = nvstrcat(p->precompiled_kernel_interface_directory, "/",
- DETACHED_SIGNATURE_FILENAME, suffix, NULL);
- rename(file, newfile);
- nvfree(newfile);
- }
+ info = nvalloc(sizeof(PrecompiledInfo));
- nvfree(file);
+ outfile = nvstrcat(p->precompiled_kernel_interface_directory, "/",
+ PRECOMPILED_PACKAGE_FILENAME, "-", p->version,
+ ".", time_str, NULL);
- file = nvstrcat(p->kernel_module_build_directory, "/",
- KERNEL_MODULE_CHECKSUM_FILENAME, NULL);
+ info->version = nvstrdup(p->version);
+ info->proc_version_string = proc_version_string;
+ info->description = descr;
+ info->num_files = num_files;
+ info->files = files;
- if (access(file, R_OK) == 0) {
- newfile = nvstrcat(p->precompiled_kernel_interface_directory, "/",
- KERNEL_MODULE_CHECKSUM_FILENAME, suffix, NULL);
- rename(file, newfile);
- nvfree(newfile);
- }
+ ret = precompiled_pack(info, outfile);
- nvfree(file);
+ nvfree(outfile);
+ free_precompiled(info);
- /* remove the old kernel interface file */
-
- file = nvstrcat(p->kernel_module_build_directory, "/",
- PRECOMPILED_KERNEL_INTERFACE_FILENAME, NULL);
-
- unlink(file); /* XXX what to do if this fails? */
-
- nvfree(file);
-
- if (ret != 0) {
- ui_error(op, "Unable to package precompiled kernel interface: %s",
- result);
+ if (ret) {
+ return TRUE;
+ }
+ else {
+ /* XXX precompiled_pack() never fails */
+ ui_error(op, "Unable to package precompiled kernel interface.");
+ return FALSE;
}
- nvfree(result);
-
- if (ret == 0) return TRUE;
- else return FALSE;
-
-} /* pack_kernel_interface() */
+}
diff --git a/files.h b/files.h
index 7f1cef4..314fb8a 100644
--- a/files.h
+++ b/files.h
@@ -21,6 +21,7 @@
#define __NVIDIA_INSTALLER_FILES_H__
#include "nvidia-installer.h"
+#include "precompiled.h"
int remove_directory(Options *op, const char *victim);
int touch_directory(Options *op, const char *victim);
@@ -54,7 +55,8 @@ char *make_tmpdir(Options *op);
int nvrename(Options *op, const char *src, const char *dst);
int check_for_existing_rpms(Options *op);
int copy_directory_contents(Options *op, const char *src, const char *dst);
-int pack_precompiled_kernel_interface(Options *op, Package *p);
+int pack_precompiled_files(Options *op, Package *p, int num_files,
+ PrecompiledFileInfo *files);
char *process_template_file(Options *op, PackageEntry *pe,
char **tokens, char **replacements);
diff --git a/install-from-cwd.c b/install-from-cwd.c
index c2d9a0d..9803a0f 100644
--- a/install-from-cwd.c
+++ b/install-from-cwd.c
@@ -127,6 +127,14 @@ int install_from_cwd(Options *op)
if (!check_for_existing_driver(op, p)) goto exit_install;
+ /*
+ * check to see if an alternate method of installation is already installed
+ * or is available, but not installed; ask the user if they really want to
+ * install anyway despite the presence/availability of an alternate install.
+ */
+
+ if (!check_for_alternate_install(op)) goto exit_install;
+
/* run the distro preinstall hook */
if (!run_distro_hook(op, "pre-install")) {
@@ -421,9 +429,15 @@ static int install_kernel_module(Options *op, Package *p)
* then there is something pretty seriously wrong... better to
* abort.
*/
-
- if (!link_kernel_module(op, p, p->kernel_module_build_directory,
- precompiled_info)) return FALSE;
+
+ 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]))) {
+ return FALSE;
+ }
+ }
} else {
/*
@@ -480,6 +494,8 @@ static int install_kernel_module(Options *op, Package *p)
int add_this_kernel(Options *op)
{
Package *p;
+ PrecompiledFileInfo *fileInfos;
+ int num_files;
/* parse the manifest */
@@ -489,13 +505,15 @@ int add_this_kernel(Options *op)
if (!determine_kernel_source_path(op, p)) goto failed;
- /* build the precompiled kernel interface */
+ /* build the precompiled files */
- if (!build_kernel_interface(op, p)) goto failed;
+ num_files = build_kernel_interface(op, p, &fileInfos);
+ if (!num_files) goto failed;
- /* pack the precompiled kernel interface */
+ /* pack the precompiled files */
- if (!pack_precompiled_kernel_interface(op, p)) goto failed;
+ if (!pack_precompiled_files(op, p, num_files, fileInfos))
+ goto failed;
free_package(p);
@@ -1096,7 +1114,7 @@ guess_fail:
cmdline = nvstrcat("cd ", p->kernel_module_build_directory, "; ",
op->utils[OPENSSL], " req -new -x509 -newkey "
- "rsa:2048 -days 7300 -nodes -sha256 -subj "
+ "rsa:2048 -days 7300 -nodes -subj "
"\"/CN=nvidia-installer generated signing key/\""
" -keyout " SECKEY_NAME " -outform DER -out "
PUBKEY_NAME, " -", x509_hash, NULL);
diff --git a/kernel.c b/kernel.c
index e8a0595..13b2dbc 100644
--- a/kernel.c
+++ b/kernel.c
@@ -48,6 +48,7 @@
static char *default_kernel_module_installation_path(Options *op);
static char *default_kernel_source_path(Options *op);
+static char *find_module_substring(char *string, const char *substring);
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 *);
@@ -55,10 +56,10 @@ static PrecompiledInfo *download_updated_kernel_interface(Options*, Package*,
const char*);
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 *output_filename,
const char *proc_version_string);
static char *build_distro_precompiled_kernel_interface_dir(Options *op);
@@ -170,6 +171,9 @@ static int run_conftest(Options *op, Package *p, const char *args, char **result
char *CC, *cmd, *arch;
int ret;
+ if (result)
+ *result = NULL;
+
arch = get_machine_arch(op);
if (!arch)
return FALSE;
@@ -186,6 +190,7 @@ static int run_conftest(Options *op, Package *p, const char *args, char **result
nvfree(cmd);
return ret == 0;
+
} /* run_conftest() */
@@ -418,7 +423,7 @@ int determine_kernel_output_path(Options *op)
* the linked module and append the signature.
*/
static int attach_signature(Options *op, Package *p,
- const PrecompiledInfo *info) {
+ const PrecompiledFileInfo *fileInfo) {
uint32 actual_crc;
char *module_filename;
int ret = FALSE, command_ret;
@@ -428,33 +433,24 @@ static int attach_signature(Options *op, Package *p,
module_filename = nvstrcat(p->kernel_module_build_directory, "/",
p->kernel_module_filename, NULL);
- command_ret = verify_crc(op, module_filename, info->linked_module_crc,
- &actual_crc);
+ command_ret = verify_crc(op, module_filename, fileInfo->linked_module_crc,
+ &actual_crc);
if (command_ret) {
- FILE *module_file, *signature_file;
+ FILE *module_file;
module_file = fopen(module_filename, "a+");
- signature_file = fopen(info->detached_signature, "r");
-
- if (module_file && signature_file) {
- char buf;
- while(fread(&buf, 1, 1, signature_file)) {
- command_ret = fwrite(&buf, 1, 1, module_file);
- if (command_ret != 1) {
- goto attach_done;
- }
+ if (module_file && fileInfo->signature_size) {
+ command_ret = fwrite(fileInfo->signature, 1,
+ fileInfo->signature_size, module_file);
+ if (command_ret != fileInfo->signature_size) {
+ goto attach_done;
}
- ret = feof(signature_file) &&
- !ferror(signature_file) &&
- !ferror(module_file);
-
- op->kernel_module_signed = ret;
+ op->kernel_module_signed = ret = !ferror(module_file);
attach_done:
fclose(module_file);
- fclose(signature_file);
} else {
ret = ui_yes_no(op, FALSE,
"A detached signature was included with the "
@@ -475,7 +471,8 @@ attach_done:
"the linker on the system that built the precompiled "
"interface.\n\nThe detached signature will not be "
"added; would you still like to install the unsigned "
- "kernel module?", actual_crc, info->linked_module_crc);
+ "kernel module?", actual_crc,
+ fileInfo->linked_module_crc);
}
if (ret) {
@@ -504,18 +501,29 @@ attach_done:
*/
int link_kernel_module(Options *op, Package *p, const char *build_directory,
- const PrecompiledInfo *info)
+ const PrecompiledFileInfo *fileInfo)
{
char *cmd, *result;
int ret;
-
+ uint32 attrmask;
+
+ if (fileInfo->type != PRECOMPILED_FILE_TYPE_INTERFACE) {
+ ui_error(op, "The file does not appear to be a valid precompiled "
+ "kernel interface.");
+ return FALSE;
+ }
+
+ ret = precompiled_file_unpack(op, fileInfo, build_directory);
+ if (!ret) {
+ ui_error(op, "Failed to unpack the precompiled interface.");
+ return FALSE;
+ }
+
p->kernel_module_filename = guess_kernel_module_filename(op);
- cmd = nvstrcat("cd ", build_directory, "; ", op->utils[LD],
- " ", LD_OPTIONS,
- " -o ", p->kernel_module_filename,
- " ", PRECOMPILED_KERNEL_INTERFACE_FILENAME,
- " nv-kernel.o", NULL);
+ 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);
@@ -528,8 +536,11 @@ int link_kernel_module(Options *op, Package *p, const char *build_directory,
ui_log(op, "Kernel module linked successfully.");
- if (info && info->detached_signature) {
- return attach_signature(op, p, info);
+ attrmask = PRECOMPILED_ATTR(DETACHED_SIGNATURE) |
+ PRECOMPILED_ATTR(LINKED_MODULE_CRC);
+
+ if ((fileInfo->attributes & attrmask) == attrmask) {
+ return attach_signature(op, p, fileInfo);
}
return TRUE;
@@ -562,13 +573,15 @@ int build_kernel_module(Options *op, Package *p)
ret = run_conftest(op, p, "select_makefile just_msg", &result);
if (!ret) {
- ui_error(op, "%s", result); /* display conftest.sh's error message */
+ if (result)
+ ui_error(op, "%s", result); /* display conftest.sh's error message */
nvfree(result);
return FALSE;
}
if (!fbdev_check(op, p)) return FALSE;
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",
@@ -687,67 +700,22 @@ int sign_kernel_module(Options *op, const char *build_directory, int status) {
/*
- * byte_tail() - write to outfile from infile, starting at the specified byte
- * offset, and going until the end of infile. This is needed because `tail -c`
- * is unreliable in some implementations.
- */
-static int byte_tail(const char *infile, const char *outfile, int start)
-{
- FILE *in = NULL, *out = NULL;
- int success = FALSE, ret;
- char buf;
-
- in = fopen(infile, "r");
- out = fopen(outfile, "w");
-
- if (!in || !out) {
- goto done;
- }
-
- ret = fseek(in, start, SEEK_SET);
- if (ret != 0) {
- goto done;
- }
-
- while(fread(&buf, 1, 1, in)) {
- ret = fwrite(&buf, 1, 1, out);
- if (ret != 1) {
- goto done;
- }
- }
-
- success = feof(in) && !ferror(in) && !ferror(out);
-
-done:
- fclose(in);
- fclose(out);
- return success;
-}
-
-
-
-/*
- * create_detached_signature() - Link the precompiled interface with nv-kernel.o,
- * sign the resulting linked nvidia.ko, and split the signature off into a separate
- * file. Copy a checksum and detached signature for the linked module to the kernel
- * module build directory on success.
+ * create_detached_signature() - Link a precompiled interface into a module,
+ * sign the resulting linked module, and store a CRC for the linked, unsigned
+ * module and the detached signature in the provided PrecompiledFileInfo record.
*/
static int create_detached_signature(Options *op, Package *p,
- const char *build_dir)
+ const char *build_dir,
+ PrecompiledFileInfo *fileInfo)
{
int ret, command_ret;
struct stat st;
- FILE *checksum_file;
- char *module_path = NULL, *tmp_path = NULL, *error = NULL, *dstfile = NULL;
+ char *module_path = NULL, *error = NULL;
ui_status_begin(op, "Creating a detached signature for the linked "
"kernel module:", "Linking module");
- tmp_path = nvstrcat(build_dir, "/", PRECOMPILED_KERNEL_INTERFACE_FILENAME,
- NULL);
- symlink(p->kernel_interface_filename, tmp_path);
-
- ret = link_kernel_module(op, p, build_dir, NULL);
+ ret = link_kernel_module(op, p, build_dir, fileInfo);
if (!ret) {
ui_error(op, "Failed to link a kernel module for signing.");
@@ -765,33 +733,8 @@ static int create_detached_signature(Options *op, Package *p,
ui_status_update(op, .25, "Generating module checksum");
- nvfree(tmp_path);
- tmp_path = nvstrcat(build_dir, "/", KERNEL_MODULE_CHECKSUM_FILENAME, NULL);
- checksum_file = fopen(tmp_path, "w");
-
- if(checksum_file) {
- uint32 crc = compute_crc(op, module_path);
- command_ret = fwrite(&crc, sizeof(crc), 1, checksum_file);
- fclose(checksum_file);
- if (command_ret != 1) {
- ret = FALSE;
- error = "Failed to write the module checksum.";
- goto done;
- }
- } else {
- ret = FALSE;
- error = "Failed to open the checksum file for writing.";
- goto done;
- }
-
- dstfile = nvstrcat(p->kernel_module_build_directory, "/",
- KERNEL_MODULE_CHECKSUM_FILENAME, NULL);
-
- if (!copy_file(op, tmp_path, dstfile, 0644)) {
- ret = FALSE;
- error = "Failed to copy the kernel module checksum file.";
- goto done;
- }
+ fileInfo->linked_module_crc = compute_crc(op, module_path);
+ fileInfo->attributes |= PRECOMPILED_ATTR(LINKED_MODULE_CRC);
ui_status_update(op, .50, "Signing linked module");
@@ -804,24 +747,15 @@ static int create_detached_signature(Options *op, Package *p,
ui_status_update(op, .75, "Detaching module signature");
- nvfree(tmp_path);
- tmp_path = nvstrcat(build_dir, "/", DETACHED_SIGNATURE_FILENAME, NULL);
- ret = byte_tail(module_path, tmp_path, st.st_size);
+ fileInfo->signature_size = byte_tail(module_path, st.st_size,
+ &(fileInfo->signature));
- if (!ret) {
+ if (!(fileInfo->signature) || fileInfo->signature_size == 0) {
error = "Failed to detach the module signature";
goto done;
}
- nvfree(dstfile);
- dstfile = nvstrcat(p->kernel_module_build_directory, "/",
- DETACHED_SIGNATURE_FILENAME, NULL);
-
- if (!copy_file(op, tmp_path, dstfile, 0644)) {
- ret = FALSE;
- error = "Failed to copy the detached signature file.";
- goto done;
- }
+ fileInfo->attributes |= PRECOMPILED_ATTR(DETACHED_SIGNATURE);
done:
if (ret) {
@@ -833,8 +767,6 @@ done:
}
}
- nvfree(dstfile);
- nvfree(tmp_path);
nvfree(module_path);
return ret;
} /* create_detached_signature() */
@@ -842,28 +774,30 @@ done:
/*
- * build_kernel_interface() - build the kernel interface, and place it
- * here:
- *
- * "%s/%s", p->kernel_module_build_directory,
- * PRECOMPILED_KERNEL_INTERFACE_FILENAME
+ * 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.
*
* This is done by copying the sources to a temporary working
- * directory, building, and copying the kernel interface back to the
- * kernel module source directory. The tmpdir is removed when
- * complete.
+ * directory and building the kernel interface in that directory.
+ * The tmpdir is removed when complete.
*
* 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)
+int build_kernel_interface(Options *op, Package *p,
+ PrecompiledFileInfo ** fileInfos)
{
char *tmpdir = NULL;
char *cmd = NULL;
- char *kernel_interface = NULL;
char *dstfile = NULL;
- int ret = FALSE;
- int command_ret;
+ int files_packaged = 0, command_ret, i;
+ const int num_files = 1; /* XXX multi-RM */
+
+ *fileInfos = NULL;
/* create a temporary directory */
@@ -892,60 +826,81 @@ int build_kernel_interface(Options *op, Package *p)
touch_directory(op, p->kernel_module_build_directory);
- /* build the kernel interface */
+ *fileInfos = nvalloc(sizeof(PrecompiledFileInfo) * num_files);
- ui_status_begin(op, "Building kernel interface:", "Building");
-
- 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);
+ for (i = 0; i < num_files; i++) {
+ char *kernel_interface, *kernel_module_filename;
+ PrecompiledFileInfo *fileInfo = *fileInfos + i;
- 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 */
- goto failed;
- }
-
- /* check that the file exists */
+ /* build the kernel interface */
- kernel_interface = nvstrcat(tmpdir, "/",
- p->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.");
- goto failed;
- }
+ ui_status_begin(op, "Building kernel interface:", "Building (%d/%d)",
+ i + 1, num_files);
- ui_status_end(op, "done.");
+ cmd = nvstrcat("cd ", tmpdir, "; make ", p->kernel_interface_filename,
+ " SYSSRC=", op->kernel_source_path, NULL);
- ui_log(op, "Kernel module interface compilation complete.");
+ command_ret = run_command(op, cmd, NULL, TRUE, 25 /* XXX */, TRUE);
- /* copy the kernel interface from the tmpdir back to the srcdir */
-
- dstfile = nvstrcat(p->kernel_module_build_directory, "/",
- PRECOMPILED_KERNEL_INTERFACE_FILENAME, NULL);
+ 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 */
+ goto failed;
+ }
- if (!copy_file(op, kernel_interface, dstfile, 0644)) goto failed;
+ /* check that the file exists */
- if (op->module_signing_secret_key && op->module_signing_public_key) {
- ret = create_detached_signature(op, p, tmpdir);
- } else {
- ret = TRUE;
+ kernel_interface = nvstrcat(tmpdir, "/",
+ p->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);
+ goto failed;
+ }
+
+ ui_status_end(op, "done.");
+
+ ui_log(op, "Kernel module interface compilation complete.");
+
+ /* add the kernel interface to the list of files to be packaged */
+
+ 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);
+
+ 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 {
+ goto failed;
+ }
}
-
- failed:
-
- remove_directory(op, tmpdir);
- if (tmpdir) nvfree(tmpdir);
+failed:
+
+ if (files_packaged == 0) {
+ nvfree(*fileInfos);
+ *fileInfos = NULL;
+ }
+
+ if (tmpdir) {
+ remove_directory(op, tmpdir);
+ nvfree(tmpdir);
+ }
if (cmd) nvfree(cmd);
- if (kernel_interface) nvfree(kernel_interface);
if (dstfile) nvfree(dstfile);
- return ret;
+ return files_packaged;
} /* build_kernel_interface() */
@@ -1470,7 +1425,7 @@ int check_for_unloaded_kernel_module(Options *op, Package *p)
PrecompiledInfo *find_precompiled_kernel_interface(Options *op, Package *p)
{
- char *proc_version_string, *output_filename, *tmp;
+ char *proc_version_string, *tmp;
PrecompiledInfo *info = NULL;
/* allow the user to completely skip this search */
@@ -1482,7 +1437,7 @@ PrecompiledInfo *find_precompiled_kernel_interface(Options *op, Package *p)
/* retrieve the proc version string for the running kernel */
- proc_version_string = read_proc_version(op);
+ proc_version_string = read_proc_version(op, op->proc_mount_point);
if (!proc_version_string) goto failed;
@@ -1491,11 +1446,6 @@ PrecompiledInfo *find_precompiled_kernel_interface(Options *op, Package *p)
if (!mkdir_recursive(op, p->kernel_module_build_directory, 0755))
goto failed;
- /* build the output filename */
-
- output_filename = nvstrcat(p->kernel_module_build_directory, "/",
- PRECOMPILED_KERNEL_INTERFACE_FILENAME, NULL);
-
/*
* if the --precompiled-kernel-interfaces-path option was
* specified, search that directory, first
@@ -1503,7 +1453,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,
- output_filename, proc_version_string);
+ proc_version_string);
}
/*
@@ -1514,7 +1464,7 @@ 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, output_filename, proc_version_string);
+ info = scan_dir(op, p, tmp, proc_version_string);
nvfree(tmp);
}
}
@@ -1528,7 +1478,7 @@ PrecompiledInfo *find_precompiled_kernel_interface(Options *op, Package *p)
if (!info) {
info = scan_dir(op, p, p->precompiled_kernel_interface_directory,
- output_filename, proc_version_string);
+ proc_version_string);
}
/*
@@ -1807,6 +1757,74 @@ static char *default_kernel_source_path(Options *op)
/*
+ * find_module_substring() - find substring in a given string where differences
+ * between hyphens and underscores are ignored. Returns a pointer to the
+ * beginning of the substring, or NULL if the string/substring is NULL, or if
+ * length of substring is greater than length of string, or substring is not
+ * found.
+ */
+
+static char *find_module_substring(char *string, const char *substring)
+{
+ int string_len, substring_len, len;
+ char *tstr;
+ const char *tsubstr;
+
+ if ((string == NULL) || (substring == NULL))
+ return NULL;
+
+ string_len = strlen(string);
+ substring_len = strlen(substring);
+
+ for (len = 0; len <= string_len - substring_len; len++, string++) {
+ if (*string != *substring) {
+ continue;
+ }
+
+ for (tstr = string, tsubstr = substring;
+ *tsubstr != '\0';
+ tstr++, tsubstr++) {
+ if (*tstr != *tsubstr) {
+ if (((*tstr == '-') || (*tstr == '_')) &&
+ ((*tsubstr == '-') || (*tsubstr == '_')))
+ continue;
+ break;
+ }
+ }
+
+ if (*tsubstr == '\0')
+ return string;
+ }
+
+ return NULL;
+} /* find_module_substring */
+
+
+/*
+ * substring_is_isolated() - given the string 'substring' with length 'len',
+ * which points to a location inside the string 'string', check to see if
+ * 'substring' is surrounded by either whitespace or the start/end of 'string'
+ * on both ends.
+ */
+
+static int substring_is_isolated(const char *substring, const char *string,
+ int len)
+{
+ if (substring != string) {
+ if (!isspace(substring[-1])) {
+ return FALSE;
+ }
+ }
+
+ if (substring[len] && !isspace(substring[len])) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
* check_for_loaded_kernel_module() - check if the specified kernel
* module is currently loaded using `lsmod`. Returns TRUE if the
* kernel module is loaded; FALSE if it is not.
@@ -1818,24 +1836,28 @@ static char *default_kernel_source_path(Options *op)
static int check_for_loaded_kernel_module(Options *op, const char *module_name)
{
- char *ptr, *result = NULL;
- int ret;
+ char *result = NULL;
+ int ret, found = FALSE;
ret = run_command(op, op->utils[LSMOD], &result, FALSE, 0, TRUE);
if ((ret == 0) && (result) && (result[0] != '\0')) {
- ptr = strstr(result, module_name);
- if (ptr) {
- ptr += strlen(module_name);
- if(!isspace(*ptr)) ret = 1;
- } else {
- ret = 1;
+ char *ptr;
+ int len = strlen(module_name);
+
+ for (ptr = result;
+ (ptr = find_module_substring(ptr, module_name));
+ ptr += len) {
+ if (substring_is_isolated(ptr, result, len)) {
+ found = TRUE;
+ break;
+ }
}
}
if (result) free(result);
- return ret ? FALSE : TRUE;
+ return found;
} /* check_for_loaded_kernel_module() */
@@ -1875,17 +1897,15 @@ download_updated_kernel_interface(Options *op, Package *p,
{
int fd = -1;
int dst_fd = -1;
- int length;
+ int length, i;
char *url = NULL;
char *tmpfile = NULL;
char *dstfile = NULL;
char *buf = NULL;
- char *output_filename = NULL;
char *str = (void *) -1;
char *ptr, *s;
struct stat stat_buf;
PrecompiledInfo *info = NULL;
- uint32 crc;
/* initialize the tmpfile and url strings */
@@ -1939,7 +1959,7 @@ download_updated_kernel_interface(Options *op, Package *p,
s += 3; /* skip past the ":::" separator */
if (strcmp(proc_version_string, s) == 0) {
-
+
/* proc versions strings match */
/*
@@ -1978,33 +1998,34 @@ download_updated_kernel_interface(Options *op, Package *p,
/* XXX once we have gpg setup, should check the file here */
- /* build the output filename string */
-
- output_filename = nvstrcat(p->kernel_module_build_directory, "/",
- PRECOMPILED_KERNEL_INTERFACE_FILENAME,
- NULL);
-
- /* unpack the downloaded file */
-
- info = precompiled_unpack(op, dstfile, output_filename,
- proc_version_string,
- p->version);
-
- /* compare checksums */
-
- crc = compute_crc(op, output_filename);
-
- if (info && (info->crc != crc)) {
- ui_error(op, "The embedded checksum of the downloaded file "
- "'%s' (%" PRIu32 ") does not match the computed "
- "checksum (%" PRIu32 "); not using.", buf, info->crc,
- crc);
- unlink(dstfile);
+ info = get_precompiled_info(op, dstfile, proc_version_string,
+ p->version);
+
+ if (!info) {
+ ui_error(op, "The format of the downloaded precompiled package "
+ "is invalid!");
free_precompiled(info);
info = NULL;
}
+ /* compare checksums */
+
+ for (i = 0; info && i < info->num_files; i++) {
+ uint32 crc = compute_crc_from_buffer(info->files[i].data,
+ info->files[i].size);
+ if (info->files[i].crc != crc) {
+ ui_error(op, "The embedded checksum of the file %s in the "
+ "downloaded precompiled pacakge '%s' (%" PRIu32
+ ") does not match the computed checksum (%"
+ PRIu32 "); not using.", info->files[i].name,
+ buf, info->files[i].crc, crc);
+ free_precompiled(info);
+ info = NULL;
+ }
+ }
+
goto done;
+
}
nvfree(buf);
@@ -2097,7 +2118,8 @@ static int fbdev_check(Options *op, Package *p)
ret = run_conftest(op, p,"rivafb_sanity_check just_msg", &result);
if (!ret) {
- ui_error(op, "%s", result);
+ if (result)
+ ui_error(op, "%s", result);
nvfree(result);
return FALSE;
@@ -2108,7 +2130,8 @@ static int fbdev_check(Options *op, Package *p)
ret = run_conftest(op, p,"nvidiafb_sanity_check just_msg", &result);
if (!ret) {
- ui_error(op, "%s", result);
+ if (result)
+ ui_error(op, "%s", result);
nvfree(result);
return FALSE;
@@ -2135,7 +2158,8 @@ static int xen_check(Options *op, Package *p)
ret = run_conftest(op, p,"xen_sanity_check just_msg", &result);
if (!ret) {
- ui_error(op, "%s", result);
+ if (result)
+ ui_error(op, "%s", result);
nvfree(result);
return FALSE;
@@ -2148,13 +2172,41 @@ static int xen_check(Options *op, Package *p)
/*
+ * preempt_rt_check() - run the preempt_rt_sanity_check conftest; if this
+ * test fails, print the test's error message and abort the driver
+ * installation.
+ */
+
+static int preempt_rt_check(Options *op, Package *p)
+{
+ char *result;
+ int ret;
+
+ ui_log(op, "Performing PREEMPT_RT check.");
+
+ ret = run_conftest(op, p, "preempt_rt_sanity_check just_msg", &result);
+
+ if (!ret) {
+ if (result)
+ ui_error(op, "%s", result);
+ nvfree(result);
+
+ return FALSE;
+ }
+
+ return TRUE;
+
+} /* preempt_rt_check() */
+
+
+
+/*
* scan_dir() - scan through the specified directory for a matching
* precompiled kernel interface.
*/
static PrecompiledInfo *scan_dir(Options *op, Package *p,
const char *directory_name,
- const char *output_filename,
const char *proc_version_string)
{
DIR *dir;
@@ -2173,21 +2225,18 @@ static PrecompiledInfo *scan_dir(Options *op, Package *p,
*/
while ((ent = readdir(dir)) != NULL) {
-
+
if (((strcmp(ent->d_name, ".")) == 0) ||
- ((strcmp(ent->d_name, "..")) == 0) ||
- strstr(ent->d_name, DETACHED_SIGNATURE_FILENAME)) continue;
+ ((strcmp(ent->d_name, "..")) == 0)) continue;
filename = nvstrcat(directory_name, "/", ent->d_name, NULL);
- info = precompiled_unpack(op, filename, output_filename,
- proc_version_string,
- p->version);
-
- if (info) break;
-
+ info = get_precompiled_info(op, filename, proc_version_string,
+ p->version);
+
free(filename);
- filename = NULL;
+
+ if (info) break;
}
if (closedir(dir) != 0) {
diff --git a/kernel.h b/kernel.h
index 9eef277..a84be97 100644
--- a/kernel.h
+++ b/kernel.h
@@ -33,11 +33,12 @@ int determine_kernel_module_installation_path (Options*);
int determine_kernel_source_path (Options*, Package*);
int determine_kernel_output_path (Options*);
int link_kernel_module (Options*, Package*,
- const char*,
- const PrecompiledInfo *);
+ const char *,
+ const PrecompiledFileInfo *);
int check_cc_version (Options*, Package*);
int build_kernel_module (Options*, Package*);
-int build_kernel_interface (Options*, Package*);
+int build_kernel_interface (Options*, Package*,
+ PrecompiledFileInfo **);
int test_kernel_module (Options*, Package*);
int load_kernel_module (Options*, Package*);
int check_for_unloaded_kernel_module (Options*, Package*);
diff --git a/misc.c b/misc.c
index 92c3065..d935415 100644
--- a/misc.c
+++ b/misc.c
@@ -447,8 +447,7 @@ int read_text_file(const char *filename, char **buf)
if (!fp)
return FALSE;
- while (((line = fget_next_line(fp, &eof))
- != NULL) && !eof) {
+ while (((line = fget_next_line(fp, &eof)) != NULL)) {
if ((index + strlen(line) + 1) > buflen) {
buflen += 2 * strlen(line);
tmpbuf = (char *)nvalloc(buflen);
@@ -466,6 +465,10 @@ int read_text_file(const char *filename, char **buf)
index += sprintf(*buf + index, "%s\n", line);
nvfree(line);
+
+ if (eof) {
+ break;
+ }
}
fclose(fp);
@@ -2391,6 +2394,9 @@ int run_nvidia_xconfig(Options *op, int restore)
} /* run_nvidia_xconfig() */
+
+#define DISTRO_HOOK_DIRECTORY "/usr/lib/nvidia/"
+
/*
* run_distro_hook() - run a distribution-provided hook script
*/
@@ -2398,7 +2404,7 @@ int run_nvidia_xconfig(Options *op, int restore)
int run_distro_hook(Options *op, const char *hook)
{
int ret, status, shouldrun = op->run_distro_scripts;
- char *cmd = nvstrcat("/usr/lib/nvidia/", hook, NULL);
+ char *cmd = nvstrcat(DISTRO_HOOK_DIRECTORY, hook, NULL);
if (op->kernel_module_only) {
ui_expert(op,
@@ -2443,6 +2449,92 @@ done:
}
+/*
+ * prompt_for_user_cancel() - print a caller-supplied message and ask the
+ * user whether to cancel the installation. If the file at the caller-supplied
+ * path is readable, include any text from that file as additional detail for
+ * the message. Returns TRUE if the user decides to cancel the installation;
+ * returns FALSE if the user decides not to cancel.
+ */
+static int prompt_for_user_cancel(Options *op, const char *file,
+ int default_cancel, const char *text)
+{
+ int ret, file_read;
+ char *message = NULL;
+
+ file_read = read_text_file(file, &message);
+
+ if (!file_read || !message) {
+ message = nvstrdup("");
+ }
+
+ ret = ui_yes_no(op, default_cancel,
+ "%s\n\n%s\nWould you like to cancel this installation?",
+ text, message);
+ nvfree(message);
+
+ return ret;
+}
+
+#define INSTALL_PRESENT_FILE "alternate-install-present"
+#define INSTALL_AVAILABLE_FILE "alternate-install-available"
+
+/*
+ * check_for_alternate_install() - check to see if an alternate install is
+ * available or present. If present, recommend updating via the alternate
+ * mechanism or uninstalling first before proceeding with an nvidia-installer
+ * installation; if available, but not present, inform the user about it.
+ * Returns TRUE if no alternate installation is available or present, or if
+ * checking for alternate installs is skipped, or if the user decides not to
+ * cancel the installation. Returns FALSE if the user decides to cancel the
+ * installation.
+ */
+
+int check_for_alternate_install(Options *op)
+{
+ int shouldcheck = op->check_for_alternate_installs;
+ const char *alt_inst_present = DISTRO_HOOK_DIRECTORY INSTALL_PRESENT_FILE;
+ const char *alt_inst_avail = DISTRO_HOOK_DIRECTORY INSTALL_AVAILABLE_FILE;
+
+ if (op->expert) {
+ shouldcheck = ui_yes_no(op, shouldcheck,
+ "Check for the availability or presence of "
+ "alternate driver installs?");
+ }
+
+ if (!shouldcheck) {
+ return TRUE;
+ }
+
+ if (access(alt_inst_present, F_OK) == 0) {
+ const char *msg;
+
+ msg = "The NVIDIA driver appears to have been installed previously "
+ "using a different installer. To prevent potential conflicts, it "
+ "is recommended either to update the existing installation using "
+ "the same mechanism by which it was originally installed, or to "
+ "uninstall the existing installation before installing this "
+ "driver.";
+
+ return !prompt_for_user_cancel(op, alt_inst_present, TRUE, msg);
+ }
+
+ if (access(alt_inst_avail, F_OK) == 0) {
+ const char *msg;
+
+ msg = "An alternate method of installing the NVIDIA driver was "
+ "detected. (This is usually a package provided by your "
+ "distributor.) A driver installed via that method may integrate "
+ "better with your system than a driver installed by "
+ "nvidia-installer.";
+
+ return !prompt_for_user_cancel(op, alt_inst_avail, FALSE, msg);
+ }
+
+ return TRUE;
+}
+
+
/*
* Determine if the nouveau driver is currently in use. We do the
diff --git a/misc.h b/misc.h
index b8c37ac..8ea12e1 100644
--- a/misc.h
+++ b/misc.h
@@ -61,6 +61,7 @@ int check_for_modular_xorg(Options *op);
int check_for_nvidia_graphics_devices(Options *op, Package *p);
int run_nvidia_xconfig(Options *op, int restore);
int run_distro_hook(Options *op, const char *hook);
+int check_for_alternate_install(Options *op);
int check_for_nouveau(Options *op);
int dkms_module_installed(Options *op, const char *version);
int dkms_install_module(Options *op, const char *version, const char *kernel);
diff --git a/mkprecompiled.c b/mkprecompiled.c
index 0c75a9f..3a4d3ca 100644
--- a/mkprecompiled.c
+++ b/mkprecompiled.c
@@ -20,32 +20,12 @@
* There is nothing specific to the NVIDIA graphics driver in this
* program, so it should be usable for the nforce drivers, for
* example.
- *
- * The format of a precompiled kernel interface package is:
- *
- * the first 8 bytes are: "NVIDIA "
- *
- * the next 4 bytes (unsigned) are: CRC of the kernel interface module
- *
- * the next 4 bytes (unsigned) are: the length of the version string (v)
- *
- * the next v bytes are the version string
- *
- * the next 4 bytes (unsigned) are: the length of the description (n)
- *
- * the next n bytes are the description
- *
- * the next 4 bytes (unsigned) are: the length of the proc version string (m)
- *
- * the next m bytes are the proc version string
- *
- * the rest of the file is the kernel interface module
*/
#define BINNAME "mkprecompiled"
#define NV_LINE_LEN 256
#define NV_VERSION_LEN 4096
-#define PROC_VERSION "/proc/version"
+#define PROC_MOUNT_POINT "/proc"
#include <stdio.h>
#include <string.h>
@@ -58,67 +38,67 @@
#include <sys/mman.h>
#include <ctype.h>
#include <stdarg.h>
+#include <inttypes.h>
-#define _GNU_SOURCE /* XXX not portable */
-#include <getopt.h>
-
-#define CONSTANT_LENGTH (8 + 4 + 4 + 4 + 4)
+#include <nvgetopt.h>
typedef unsigned int uint32;
typedef unsigned char uint8;
+enum {
+ PACK = 'p',
+ UNPACK = 'u',
+ INFO = 'i',
+ MATCH = 'm',
+};
+
/*
* Options structure
*/
typedef struct {
- char *interface;
- char *output;
- char *unpack;
+ int action;
+ char *package_file;
+ char *output_directory;
char *description;
char *proc_version_string;
+ char *proc_mount_point;
char *version;
- uint8 info;
- uint8 match;
+ int num_files;
+ struct __precompiled_file_info *new_files;
+ struct __precompiled_info *package;
} Options;
+#include "common-utils.h"
#include "crc.h"
+#include "precompiled.h"
+
/*
- * nv_alloc() - malloc wrapper that checks for errors, and zeros out
- * the memory; if an error occurs, an error is printed to stderr and
- * exit() is called -- this function will only return on success.
+ * XXX hack to resolve symbols used by crc.c and precompiled.c
*/
-static void *nv_alloc (size_t size)
-{
- void *m = malloc (size);
-
- if (!m) {
- fprintf (stderr, "%s: memory allocation failure\n", BINNAME);
- exit (1);
- }
- memset (m, 0, size);
- return (m);
-
-} /* nv_alloc() */
+void ui_warn(Options *op, const char *fmt, ...);
+void ui_warn(Options *op, const char *fmt, ...)
+{
+ va_list ap;
-/*
- * XXX hack to resolve symbols used by crc.c
- */
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
-void *nvalloc(size_t size);
+void ui_expert(Options *op, const char *fmt, ...);
-void *nvalloc(size_t size)
+void ui_expert(Options *op, const char *fmt, ...)
{
- return nv_alloc(size);
}
-void ui_warn(Options *op, const char *fmt, ...);
+void ui_error(Options *op, const char *fmt, ...);
-void ui_warn(Options *op, const char *fmt, ...)
+void ui_error(Options *op, const char *fmt, ...)
{
va_list ap;
@@ -127,610 +107,577 @@ void ui_warn(Options *op, const char *fmt, ...)
va_end(ap);
}
+void ui_log(Options *op, const char *fmt, ...);
-
-/*
- * nv_open() - open(2) wrapper; prints an error message if open(2)
- * fails and calls exit(). This function only returns on success.
- */
-
-static int nv_open(const char *pathname, int flags, mode_t mode)
+void ui_log(Options *op, const char *fmt, ...)
{
- int fd;
- fd = open(pathname, flags, mode);
- if (fd == -1) {
- fprintf(stderr, "Failure opening %s (%s).\n",
- pathname, strerror(errno));
- exit(1);
- }
- return fd;
+}
-} /* nv_name() */
/*
- * nv_get_file_length() - stat(2) wrapper; prints an error message if
- * the system call fails and calls exit(). This function only returns
- * on success.
+ * print_help()
*/
-static int nv_get_file_length(const char *filename)
+static void print_help(void)
{
- struct stat stat_buf;
- int ret;
-
- ret = stat(filename, &stat_buf);
- if (ret == -1) {
- fprintf(stderr, "Unable to determine '%s' file length (%s).\n",
- filename, strerror(errno));
- exit(1);
- }
- return stat_buf.st_size;
+ printf("\n%s: pack/unpack precompiled files, and get information about\n"
+ "existing precompiled file packages.\n\n"
+ "USAGE: <action> <package-file> [options] \n\n", BINNAME);
+
+ printf("<action> may be one of:\n\n"
+ " -p | --pack add files to a package\n"
+ " -u | --unpack unpack files from a package\n"
+ " -i | --info display information about a package\n"
+ " -m | --match check if a package matches the running kernel\n"
+ " -h | --help print this help text and exit\n\n"
+ "<package-file> is the package file to pack/unpack/test. It must be\n"
+ "an existing, valid package file for the --unpack, --info, and\n"
+ "--match actions. For the --pack action, if <package-file> does not\n"
+ "exist, it is created; if it exists but is not a valid package file,\n"
+ "it is overwritten; and if it exists and is a valid package file,\n"
+ "files will be added to the existing package.\n\n"
+ "--pack options:\n"
+ " -v | --driver-version (REQUIRED for new packages)\n"
+ " The version of the packaged components.\n"
+ " -P | --proc-version-string (RECOMMENDED for new packages)\n"
+ " The kernel version, as reported by '/proc/version', for the\n"
+ " target kernel. Default: the contents of the '/proc/version'\n"
+ " file on the current system.\n"
+ " -d | --description (RECOMMENDED for new packages)\n"
+ " A human readable description of the package.\n"
+ " --kernel-interface <file> --linked-module-name <module-name>\\\n"
+ " --core-object-name <core-name>\\\n"
+ " [ --linked-module <linked-kmod-file> \\\n"
+ " --signed-module <signed-kmod-file> ]\n"
+ " Pack <file> as a precompiled kernel interface.\n"
+ " <module-name> specifies the name of the kernel module file\n"
+ " that is produced by linking the precompiled kernel interface\n"
+ " with a separate precompiled core object file. <core-name>\n"
+ " specifies the name of the core object file that is linked\n"
+ " together with the precompiled interface to produce the final\n"
+ " kernel module.\n"
+ " A detached module signature may be produced by specifying\n"
+ " both the --linked-module and --signed-module options.\n"
+ " <linked-kmod-file> is a linked .ko file that is the result\n"
+ " of linking the precompiled interface with the remaining\n"
+ " object file(s) required to produce the finished module, and\n"
+ " <signed-kmod-file> is a copy of <linked-kmod-file> which an\n"
+ " appended module signature. In order for the signature to be\n"
+ " correctly applied on the target system, the linking should\n"
+ " be performed with the same linker and flags that will be\n"
+ " used on the target system.\n"
+ " The --linked-module and --signed-module options must be\n"
+ " given after the --kernel-interface option for the kernel\n"
+ " interface file with which they are associated, and before\n"
+ " any additional --kernel-interface or --kernel-module files.\n"
+ " --kernel-module <file> [ --signed ]\n"
+ " Pack <file> as a precompiled kernel module. The --signed\n"
+ " option specifies that <file> includes a module signature.\n"
+ " The --signed option must be given after the --kernel-module\n"
+ " option for the kernel module with which it is associated,\n"
+ " and before any additional --kernel-interface or\n"
+ " --kernel-module files.\n\n"
+ " If --driver-version, --proc-version-string, or --description\n"
+ " are given with an existing package file, the values in that\n"
+ " package file will be updated with new ones. At least one file\n"
+ " must be given with either --kernel-interface or --kernel-module\n"
+ " when using the --pack option.\n\n"
+ "--unpack options:\n"
+ " -o | --output-directory\n"
+ " The target directory where files will be unpacked. Default:\n"
+ " unpack files in the current directory.\n\n"
+ "Additional options:\n"
+ " --proc-mount-point\n"
+ " The procfs mount point on the current system, where the \n"
+ " '/proc/version' file may be found. Used by the --match\n"
+ " action, as well as to supply the default value of the\n"
+ " --proc-version-string option of the --pack action.\n"
+ " Default value: '/proc'\n");
-} /* nv_get_file_length() */
+} /* print_help() */
+enum {
+ PROC_MOUNT_POINT_OPTION = 1024,
+ KERNEL_INTERFACE_OPTION,
+ KERNEL_MODULE_OPTION,
+ SIGNED_FILE_OPTION,
+ LINKED_MODULE_OPTION,
+ LINKED_AND_SIGNED_MODULE_OPTION,
+ LINKED_MODULE_NAME_OPTION,
+ CORE_OBJECT_NAME_OPTION,
+};
-/*
- * nv_set_file_length() - wrapper for lseek() and write(); prints an
- * error message if the system calls fail and calls exit(). This
- * function only returns on success.
- */
-static void nv_set_file_length(const char *filename, int fd, int len)
+static void grow_file_array(Options *op, int *array_size)
{
- if ((lseek(fd, len - 1, SEEK_SET) == -1) ||
- (write(fd, "", 1) == -1)) {
- fprintf(stderr, "Unable to set file '%s' length %d (%s).\n",
- filename, fd, strerror(errno));
- exit(1);
+ if (op->num_files < 0) {
+ op->num_files = 0;
}
-} /* nv_set_file_length() */
+ if (op->num_files >= *array_size) {
+ *array_size *= 2;
+ op->new_files = nvrealloc(op->new_files,
+ sizeof(PrecompiledFileInfo) * *array_size);
+ }
+}
-/*
- * nv_mmap() - mmap(2) wrapper; prints an error message if mmap(2)
- * fails and calls exit(). This function only returns on success.
- */
+static uint32 file_type_from_option(int option) {
+ switch (option) {
+ case KERNEL_INTERFACE_OPTION:
+ return PRECOMPILED_FILE_TYPE_INTERFACE;
+ case KERNEL_MODULE_OPTION:
+ return PRECOMPILED_FILE_TYPE_MODULE;
+ default:
+ fprintf(stderr, "Unrecognized file type!");
+ exit(1);
+ }
+}
-static void *nv_mmap(const char *filename, size_t len, int prot,
- int flags, int fd)
-{
- void *ret;
- ret = mmap(0, len, prot, flags, fd, 0);
- if (ret == (void *) -1) {
- fprintf(stderr, "Unable to mmap file %s (%s).\n",
- filename, strerror(errno));
+static void check_file_option_validity(Options *op, const char *option_name)
+{
+ if (op->num_files < 0) {
+ fprintf(stderr, "The --%s option cannot be specified before a file "
+ "name.\n", option_name);
exit(1);
}
- return ret;
-
-} /* nv_mmap() */
-
-
+}
-/*
- * print_help()
- */
-static void print_help(void)
+static int create_detached_signature(Options *op, PrecompiledFileInfo *file,
+ const char *linked_module,
+ const char *signed_module)
{
- printf("\n%s [options] \n\n", BINNAME);
-
- printf("-i, --interface=<interface name>\n");
- printf(" Name of kernel interface file.\n\n");
-
- printf("-o, --output=<output name>\n");
- printf(" Name of output file.\n\n");
-
- printf("-u, --unpack=<filename>\n");
- printf(" Name of file to be unpacked.\n\n");
-
- printf("-d, --description=<kernel description>\n");
- printf(" Kernel description.\n\n");
+ if (file->type != PRECOMPILED_FILE_TYPE_INTERFACE) {
+ return TRUE;
+ } else if (linked_module && signed_module) {
+ struct stat st;
+
+ if (stat(linked_module, &st) != 0) {
+ fprintf(stderr, "Unable to stat the linked kernel module file '%s'."
+ "\n", linked_module);
+ return FALSE;
+ }
- printf("-v, --proc-version=<string>\n");
- printf(" /proc/version string for target kernel.\n\n");
+ file->linked_module_crc = compute_crc(op, linked_module);
+ file->attributes |= PRECOMPILED_ATTR(LINKED_MODULE_CRC);
- printf("--version=<version string>\n\n");
-
- printf("--info\n");
- printf(" Print the description and version number of the file\n");
- printf(" specified by the unpack option.\n\n");
+ file->signature_size = byte_tail(signed_module, st.st_size,
+ &(file->signature));
- printf("-m, --match\n");
- printf(" Check if the precompiled package matches the running\n");
- printf(" kernel.\n\n");
+ if (file->signature_size > 0 && file->signature != NULL) {
+ file->attributes |= PRECOMPILED_ATTR(DETACHED_SIGNATURE);
+ return TRUE;
+ } else {
+ fprintf(stderr, "Failed to create a detached signature from signed "
+ "kernel module '%s'.\n", signed_module);
+ }
- printf("This program can be used to either pack a precompiled kernel\n");
- printf("module interface, or unpack it.\n\n");
+ } else if (linked_module || signed_module) {
+ fprintf(stderr, "Both --linked-module and --signed-module must be "
+ "specified to create a detached signature for precompiled "
+ "kernel interface file '%s'.\n", file->name);
+ } else {
+ return TRUE;
+ }
-} /* print_help() */
+ return FALSE;
+}
+static void set_action(Options *op, int action)
+{
+ if (op->action) {
+ fprintf(stderr, "Invalid command line; multiple actions cannot be "
+ "specified at the same time.\n");
+ exit(1);
+ }
-/*
- * parse_commandline() - parse the commandline arguments. do some
- * trivial validation, and return an initialized malloc'ed Options
- * structure.
- */
+ op->action = action;
+}
-static Options *parse_commandline(int argc, char *argv[])
+static void pack_a_file(Options *op, PrecompiledFileInfo *file,
+ char *name, uint32 type, char **linked_name,
+ char **core_name, char **linked_module_file,
+ char **signed_module_file)
{
- Options *op;
- int c, option_index = 0;
+ switch(type) {
+ case PRECOMPILED_FILE_TYPE_INTERFACE:
+ if (*linked_name == NULL || *core_name == NULL) {
+ fprintf(stderr, "Each kernel interface file must have both the "
+ "--linked-module-name and --core-object-name options set "
+ "in order to be added to a package.\n");
+ exit(1);
+ }
-#define INFO_OPTION 4
-
- static struct option long_options[] = {
- { "interface", 1, 0, 'i' },
- { "output", 1, 0, 'o' },
- { "unpack", 1, 0, 'u' },
- { "description", 1, 0, 'd' },
- { "help", 0, 0, 'h' },
- { "proc-version", 1, 0, 'v' },
- { "version", 1, 0, 'V' },
- { "info", 0, 0, INFO_OPTION },
- { "match", 0, 0, 'm' },
- { 0, 0, 0, 0 }
- };
-
- op = (Options *) nv_alloc(sizeof(Options));
-
- while (1) {
- c = getopt_long (argc, argv, "i:b:o:u:d:hv:m",
- long_options, &option_index);
- if (c == -1)
- break;
+ if (!precompiled_read_interface(file, name, *linked_name, *core_name)) {
+ fprintf(stderr, "Failed to read kernel interface '%s'.\n", name);
+ exit(1);
+ }
+ break;
- switch(c) {
- case 'i': op->interface = optarg; break;
- case 'o': op->output = optarg; break;
- case 'u': op->unpack = optarg; break;
- case 'd': op->description = optarg; break;
- case 'h': print_help(); exit(0); break;
- case 'v': op->proc_version_string = optarg; break;
- case 'V': op->version = optarg; break;
- case INFO_OPTION:
- op->info = 1; break;
- case 'm':
- op->match = 1; break;
- default:
- fprintf (stderr, "Invalid commandline, please run `%s --help` "
- "for usage information.\n", argv[0]);
- exit (0);
+ case PRECOMPILED_FILE_TYPE_MODULE:
+ if (!precompiled_read_module(file, name)) {
+ fprintf(stderr, "Failed to read kernel module '%s'.\n", name);
}
- }
+ break;
- if (optind < argc) {
- fprintf (stderr, "Unrecognized arguments: ");
- while (optind < argc)
- fprintf (stderr, "%s ", argv[optind++]);
- fprintf (stderr, "\n");
- fprintf (stderr, "Invalid commandline, please run `%s --help` for "
- "usage information.\n", argv[0]);
- exit (0);
- }
-
- /* validate options */
-
- if (!op->unpack && !(op->interface && op->proc_version_string)) {
-
- fprintf (stderr, "Incorrect options specified; please run "
- "`%s --help` for usage information.\n", argv[0]);
- exit(1);
- }
-
- if (!op->info && !op->match && !op->output) {
- fprintf(stderr, "Output file not specified.\n");
+ default:
exit(1);
}
+ nvfree(name);
- if (!op->version) {
- fprintf(stderr, "Driver version string not specified.\n");
+ if (!create_detached_signature(op, file, *linked_module_file,
+ *signed_module_file)) {
exit(1);
}
- return op;
-
-} /* parse_commandline() */
+ op->num_files++;
+ nvfree(*linked_name);
+ nvfree(*core_name);
+ nvfree(*linked_module_file);
+ nvfree(*signed_module_file);
+ *linked_name = *core_name = *linked_module_file = *signed_module_file = NULL;
+}
+/*
+ * parse_commandline() - parse the commandline arguments. do some
+ * trivial validation, and return an initialized malloc'ed Options
+ * structure.
+ */
-static char *read_proc_version(void)
+static Options *parse_commandline(int argc, char *argv[])
{
- int fd, ret, len, version_len;
- char *version, *c = NULL;
-
- fd = nv_open(PROC_VERSION, O_RDONLY, 0);
-
- /*
- * it would be more convenient if we could just mmap(2)
- * /proc/version, but that's not supported, so just read in the
- * whole file
- */
-
- len = version_len = 0;
- version = NULL;
+ Options *op;
+ int c, file_array_size = 16;
+ uint32 type = 0;
+ PrecompiledFileInfo *file = NULL;
+ char *strval, *signed_mod = NULL, *linked_mod = NULL, *filename = NULL,
+ *linked_name = NULL, *core_name = NULL;
+ char see_help[1024];
+
+ static const NVGetoptOption long_options[] = {
+ { "pack", PACK, NVGETOPT_STRING_ARGUMENT, NULL, NULL },
+ { "unpack", UNPACK, NVGETOPT_STRING_ARGUMENT, NULL, NULL },
+ { "info", INFO, NVGETOPT_STRING_ARGUMENT, NULL, NULL },
+ { "match", MATCH, NVGETOPT_STRING_ARGUMENT, NULL, NULL },
+ { "help", 'h', 0, NULL, NULL },
+ { "description", 'd', NVGETOPT_STRING_ARGUMENT, NULL, NULL },
+ { "output-directory", 'o', NVGETOPT_STRING_ARGUMENT, NULL, NULL },
+ { "driver-version", 'v', NVGETOPT_STRING_ARGUMENT, NULL, NULL },
+ { "proc-version-string", 'P', NVGETOPT_STRING_ARGUMENT, NULL, NULL },
+ { "proc-mount-point", PROC_MOUNT_POINT_OPTION,
+ NVGETOPT_STRING_ARGUMENT, NULL, NULL },
+ { "kernel-interface", KERNEL_INTERFACE_OPTION,
+ NVGETOPT_STRING_ARGUMENT, NULL, NULL },
+ { "kernel-module", KERNEL_MODULE_OPTION,
+ NVGETOPT_STRING_ARGUMENT, NULL, NULL },
+ { "signed", SIGNED_FILE_OPTION,
+ 0, NULL, NULL },
+ { "linked-module", LINKED_MODULE_OPTION,
+ NVGETOPT_STRING_ARGUMENT, NULL, NULL },
+ { "signed-module", LINKED_AND_SIGNED_MODULE_OPTION,
+ NVGETOPT_STRING_ARGUMENT, NULL, NULL },
+ { "linked-module-name", LINKED_MODULE_NAME_OPTION,
+ NVGETOPT_STRING_ARGUMENT, NULL, NULL },
+ { "core-object-name", CORE_OBJECT_NAME_OPTION,
+ NVGETOPT_STRING_ARGUMENT, NULL, NULL },
+ { NULL, 0, 0, NULL, NULL }
+ };
- while (1) {
- if (version_len == len) {
- version_len += NV_VERSION_LEN;
- version = realloc(version, version_len);
- c = version + len;
- }
- ret = read(fd, c, version_len - len);
- if (ret == -1) {
- fprintf(stderr, "Error reading %s (%s).\n",
- PROC_VERSION, strerror(errno));
- free(version);
- return NULL;
- }
- if (ret == 0) {
- *c = '\0';
- break;
- }
- len += ret;
- c += ret;
- }
+ snprintf(see_help, sizeof(see_help), "Please run `%s --help` for usage "
+ "information.\n", argv[0]);
+ see_help[sizeof(see_help) - 1] = '\0';
- /* replace a newline with a null-terminator */
+ op = (Options *) nvalloc(sizeof(Options));
+ op->new_files = nvalloc(sizeof(PrecompiledFileInfo) * file_array_size);
+ op->num_files = -1;
- c = version;
- while ((*c != '\0') && (*c != '\n')) c++;
- *c = '\0';
+ op->proc_mount_point = PROC_MOUNT_POINT;
- return version;
+ while (1) {
+ c = nvgetopt(argc, argv, long_options, &strval,
+ NULL, /* boolval */
+ NULL, /* intval */
+ NULL, /* doubleval */
+ NULL /* disable_val */);
-} /* read_proc_version() */
+ if (c == -1)
+ break;
+ switch(c) {
+ case PACK: case UNPACK: case INFO: case MATCH:
+ set_action(op, c);
+ op->package_file = strval;
+ break;
+ case 'h': print_help(); exit(0); break;
+ case 'f': op->package_file = strval; break;
+ case 'd': op->description = strval; break;
+ case 'o': op->output_directory = strval; break;
+ case 'v': op->version = strval; break;
+ case 'P': op->proc_version_string = strval; break;
+ case PROC_MOUNT_POINT_OPTION: op->proc_mount_point = strval; break;
-/*
- * check_match() - read /proc/version, and do a strcmp with str.
- * Returns 1 if the strings match, 0 if they don't match.
- */
+ case KERNEL_INTERFACE_OPTION: case KERNEL_MODULE_OPTION:
-static int check_match(char *str)
-{
- int ret = 0;
- char *version = read_proc_version();
-
- if (strcmp(version, str) == 0) {
- ret = 1;
- printf("kernel interface matches.\n");
- } else {
- ret = 0;
- printf("kernel interface doesn't match.\n");
- }
+ grow_file_array(op, &file_array_size);
- free(version);
-
- return ret;
-
-} /* check_match() */
+ if (file) {
+ pack_a_file(op, file, filename, type, &linked_name, &core_name,
+ &linked_mod, &signed_mod);
+ }
+ file = op->new_files + op->num_files;
+ filename = strval;
+ type = file_type_from_option(c);
+ break;
-/*
- * encode_uint32() - given a uint32, and a 4 byte data buffer, write
- * the integer to the data buffer.
- */
+ case SIGNED_FILE_OPTION:
-static void encode_uint32(uint32 val, uint8 data[4])
-{
- data[0] = ((val >> 0) & 0xff);
- data[1] = ((val >> 8) & 0xff);
- data[2] = ((val >> 16) & 0xff);
- data[3] = ((val >> 24) & 0xff);
+ check_file_option_validity(op, "signed");
-} /* encode_uint32() */
+ /*
+ * for interfaces, signedness is implied by the presence of a linked
+ * module crc and a detached signature, so only set the signed file
+ * attribute in the case of a precompiled kernel module.
+ */
+ if (type == PRECOMPILED_FILE_TYPE_MODULE) {
+ file->attributes |= PRECOMPILED_ATTR(EMBEDDED_SIGNATURE);
+ }
+ break;
-/*
- * decode_uint32() - given an index into a buffer, read the next 4
- * bytes, and build a uint32.
- */
+ case LINKED_MODULE_OPTION:
-static uint32 decode_uint32(char *buf)
-{
- uint32 ret = 0;
+ check_file_option_validity(op, "linked-module");
+ linked_mod = strval;
- ret += (((uint32) buf[3]) & 0xff);
- ret <<= 8;
+ break;
- ret += (((uint32) buf[2]) & 0xff);
- ret <<= 8;
+ case LINKED_AND_SIGNED_MODULE_OPTION:
- ret += (((uint32) buf[1]) & 0xff);
- ret <<= 8;
+ check_file_option_validity(op, "signed-module");
+ signed_mod = strval;
- ret += (((uint32) buf[0]) & 0xff);
- ret <<= 0;
+ break;
- return ret;
+ case LINKED_MODULE_NAME_OPTION:
-} /* decode_uint32() */
+ check_file_option_validity(op, "linked-module-name");
+ linked_name = strval;
+ break;
+ case CORE_OBJECT_NAME_OPTION:
-/*
- * pack() - pack the specified precompiled kernel interface file,
- * prepended with a header, the CRC the driver version, a description
- * string, and the proc version string.
- */
+ check_file_option_validity(op, "core-object-name");
+ core_name = strval;
-static int pack(Options *op)
-{
- int fd, offset, src_fd;
- uint8 *out, *src, data[4];
- uint32 crc;
- int version_len, description_len, proc_version_len;
- int interface_len, total_len;
-
- /*
- * get the lengths of the description, the proc version string,
- * and the interface file.
- */
-
- version_len = strlen(op->version);
- description_len = strlen(op->description);
- proc_version_len = strlen(op->proc_version_string);
- interface_len = nv_get_file_length(op->interface);
-
- total_len = CONSTANT_LENGTH +
- version_len + description_len + proc_version_len + interface_len;
-
- /* compute the crc of the kernel interface */
+ break;
- crc = compute_crc(NULL, op->interface);
+ default:
+ fprintf (stderr, "Invalid commandline; %s", see_help);
+ exit(0);
+ }
+ }
- /* open the output file for writing */
-
- fd = nv_open(op->output, O_CREAT|O_RDWR|O_TRUNC,
- S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
- /* set the output file length */
+ /* validate options */
- nv_set_file_length(op->output, fd, total_len);
-
- /* map the input file */
+ if (!op->action) {
+ fprintf(stderr, "No action specified; one of --pack, --unpack, --info, "
+ "or --match options must be given. %s", see_help);
+ exit(1);
+ }
- out = nv_mmap(op->output, total_len, PROT_READ|PROT_WRITE,
- MAP_FILE|MAP_SHARED, fd);
- offset = 0;
+ switch (op->action) {
+ case PACK:
+ if (file) {
+ pack_a_file(op, file, filename, type, &linked_name, &core_name,
+ &linked_mod, &signed_mod);
+ }
- /* write the header */
-
- memcpy(&(out[0]), "NVIDIA ", 8);
- offset += 8;
+ if (op->num_files < 1) {
+ fprintf(stderr, "At least one file to pack must be specified "
+ "when using the --pack option; %s", see_help);
+ exit(1);
+ }
+ break;
- /* write the crc */
+ case UNPACK:
+ if (!op->output_directory) {
+ op->output_directory = ".";
+ }
+ break;
- encode_uint32(crc, data);
- memcpy(&(out[offset]), data, 4);
- offset += 4;
+ case INFO: case MATCH: default: /* XXX should never hit default case */
+ break;
+ }
- /* write the version */
+ op->package = get_precompiled_info(op, op->package_file, NULL, NULL);
- encode_uint32(version_len, data);
- memcpy(&(out[offset]), data, 4);
- offset += 4;
-
- if (version_len) {
- memcpy(&(out[offset]), op->version, version_len);
- offset += version_len;
+ if (!op->package && op->action != PACK) {
+ fprintf(stderr, "Unable to read package file '%s'.\n",
+ op->package_file);
+ exit(1);
}
- /* write the description */
+ return op;
- encode_uint32(description_len, data);
- memcpy(&(out[offset]), data, 4);
- offset += 4;
+} /* parse_commandline() */
- if (description_len) {
- memcpy(&(out[offset]), op->description, description_len);
- offset += description_len;
- }
- /* write the proc version string */
-
- encode_uint32(proc_version_len, data);
- memcpy(&(out[offset]), data, 4);
- offset += 4;
-
- memcpy(&(out[offset]), op->proc_version_string, proc_version_len);
- offset += proc_version_len;
- /* open the precompiled kernel module interface for reading */
- src_fd = nv_open(op->interface, O_RDONLY, 0);
-
- /* mmap() the kernel module interface */
+/*
+ * check_match() - read /proc/version, and do a strcmp with str.
+ * Returns 1 if the strings match, 0 if they don't match.
+ */
- src = nv_mmap(op->interface, interface_len, PROT_READ,
- MAP_FILE|MAP_SHARED, src_fd);
+static int check_match(Options *op, char *str)
+{
+ int ret = 0;
+ char *version = read_proc_version(op, op->proc_mount_point);
- memcpy(out + offset, src, interface_len);
-
- /* unmap src and dst */
+ if (strcmp(version, str) == 0) {
+ ret = 1;
+ printf("kernel interface matches.\n");
+ } else {
+ ret = 0;
+ printf("kernel interface doesn't match.\n");
+ }
- munmap(src, interface_len);
- munmap(out, total_len);
+ free(version);
+
+ return ret;
- close(src_fd);
- close(fd);
-
- return 0;
-
-} /* pack() */
+} /* check_match() */
/*
- * unpack() - unpack the specified package
+ * program entry point
*/
-static int unpack(Options *op)
+int main(int argc, char *argv[])
{
- int dst_fd, fd, ret, offset, len = 0;
- char *buf, *dst;
- uint32 crc, val, size;
- char *version, *description, *proc_version_string;
-
- fd = dst_fd = 0;
- buf = dst = NULL;
- ret = 1;
-
- /* open the file to be unpacked */
-
- fd = nv_open(op->unpack, O_RDONLY, 0);
-
- /* get the file length */
-
- size = nv_get_file_length(op->unpack);
+ Options *op;
+ int ret = 1;
- /* check for a minimum length */
+ op = parse_commandline(argc, argv);
- if (size < CONSTANT_LENGTH) {
- fprintf(stderr, "File '%s' appears to be too short.\n", op->unpack);
- goto done;
- }
-
- /* mmap(2) the input file */
- buf = nv_mmap(op->unpack, size, PROT_READ, MAP_FILE|MAP_SHARED, fd);
- offset = 0;
+ switch (op->action) {
+ int i;
+
+ case PACK:
+ if (!op->package) {
+ if (!op->version) {
+ fprintf (stderr, "The --driver-version option must be specified "
+ "when using the --pack option to create a new package; "
+ "Please run `%s --help` for usage information.\n",
+ argv[0]);
+ exit (1);
+ }
+
+ op->package = nvalloc(sizeof(PrecompiledInfo));
+
+ op->package->description = op->description ? op->description :
+ nvstrdup("");
+ op->package->proc_version_string =
+ op->proc_version_string ?
+ op->proc_version_string :
+ read_proc_version(op, op->proc_mount_point);
+ op->package->version = op->version;
+ }
- /* check for the header */
+ precompiled_append_files(op->package, op->new_files, op->num_files);
- if (strncmp(buf, "NVIDIA ", 8) != 0) {
- fprintf(stderr, "File '%s': unrecognized file format.\n", op->unpack);
- goto done;
- }
- offset += 8;
+ if (precompiled_pack(op->package, op->package_file)) {
+ ret = 0;
+ } else {
+ fprintf(stderr, "An error occurred while writing the package "
+ "file '%s'.\n", op->package_file);
+ }
- /* read the crc */
+ break;
- crc = decode_uint32(buf + offset);
- offset += 4;
-
- /* read the version */
+ case UNPACK:
+ if (precompiled_unpack(op, op->package, op->output_directory)) {
+ ret = 0;
+ } else {
+ fprintf(stderr, "An error occurred while unpacking the package "
+ "file '%s' to '%s'.\n", op->package_file,
+ op->output_directory);
+ }
+ break;
- val = decode_uint32(buf + offset);
- offset += 4;
+ case INFO:
- if (val > 0) {
- version = nv_alloc(val+1);
- memcpy(version, buf + offset, val);
- version[val] = '\0';
- } else {
- version = NULL;
- }
- offset += val;
+ printf("description: %s\n", op->package->description);
+ printf("version: %s\n", op->package->version);
+ printf("proc version: %s\n", op->package->proc_version_string);
+ printf("number of files: %d\n\n", op->package->num_files);
- /* read the description */
+ for (i = 0; i < op->package->num_files; i++) {
+ PrecompiledFileInfo *file = op->package->files + i;
+ const char **attrs, **attr;
- val = decode_uint32(buf + offset);
- offset += 4;
- if ((val + CONSTANT_LENGTH) > size) {
- fprintf(stderr, "Invalid file.\n");
- goto done;
- }
- if (val > 0) {
- description = nv_alloc(val+1);
- memcpy(description, buf + offset, val);
- description[val] = '\0';
- } else {
- description = NULL;
- }
- offset += val;
-
- /* read the proc version string */
+ attrs = precompiled_file_attribute_names(file->attributes);
- val = decode_uint32(buf + offset);
- offset += 4;
- if ((val + CONSTANT_LENGTH) > size) {
- fprintf(stderr, "Invalid file.\n");
- goto done;
- }
- proc_version_string = nv_alloc(val+1);
- memcpy(proc_version_string, buf + offset, val);
- offset += val;
- proc_version_string[val] = '\0';
-
- /*
- * if info was requested, print the description, driver version,
- * crc, proc version, and exit
- */
-
- if (op->info) {
- printf("description: %s\n", description);
- printf("version: %s\n", version);
- printf("crc: %u\n", crc);
- printf("proc version: %s\n", proc_version_string);
- return 0;
- }
-
- /* check if the running kernel matches */
+ printf("file %d:\n", i + 1);
+ printf(" name: '%s'\n", file->name);
+ printf(" type: %s\n",
+ precompiled_file_type_name(file->type));
+ printf(" attributes: ");
- if (op->match) {
- return check_match(proc_version_string);
- }
-
- /* extract kernel interface module */
-
- len = size - offset;
+ for(attr = attrs; *attr; attr++) {
+ if (attr > attrs) {
+ printf(", ");
+ }
+ printf("%s", *attr);
+ }
- dst_fd = nv_open(op->output, O_CREAT | O_RDWR | O_TRUNC,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
- /* set the output file length */
+ printf("\n");
- nv_set_file_length(op->output, dst_fd, len);
-
- /* mmap the dst */
+ printf(" size: %d bytes\n", file->size);
+ printf(" crc: %" PRIu32 "\n", file->crc);
- dst = nv_mmap(op->output, len, PROT_READ|PROT_WRITE,
- MAP_FILE|MAP_SHARED, dst_fd);
-
- /* copy */
-
- memcpy(dst, buf + offset, len);
-
- ret = 0;
+ if (file->type == PRECOMPILED_FILE_TYPE_INTERFACE) {
+ printf(" core object name: %s\n", file->core_object_name);
+ printf(" linked module name: %s\n", file->linked_module_name);
+ if (file->signature_size) {
+ printf(" linked module crc: %" PRIu32 "\n",
+ file->linked_module_crc);
+ printf(" signature size: %d\n", file->signature_size);
+ }
+ }
- done:
- if (dst) munmap(dst, len);
- if (buf) munmap(buf, size);
- if (fd > 0) close(fd);
- if (dst_fd > 0) close(dst_fd);
- return ret;
-
-} /* unpack() */
+ printf("\n");
+ }
+ ret = 0;
+ break;
-/*
- * program entry point
- */
+ case MATCH:
-int main(int argc, char *argv[])
-{
- Options *op;
- int ret;
+ ret = check_match(op, op->package->proc_version_string);
+ break;
- op = parse_commandline(argc, argv);
+ default: /* XXX should never get here */ break;
- if (op->unpack) {
- ret = unpack(op);
- } else { /* pack */
- ret = pack(op);
}
+
+ free_precompiled(op->package);
return ret;
diff --git a/nvidia-installer.1.m4 b/nvidia-installer.1.m4
index 61c4ed6..07f1291 100644
--- a/nvidia-installer.1.m4
+++ b/nvidia-installer.1.m4
@@ -122,6 +122,16 @@ These scripts should not require user interaction.
Use the
.B \-\-no\-distro\-scripts
option to disable execution of these scripts.
+.PP
+In addition to the distribution hook scripts, distributors or other producers of driver packages may report the presence an already installed driver, or the availability of driver packages. Installing a text file to
+.B /usr/lib/nvidia/alternate-install-present
+will alert nvidia-installer that an existing driver is already installed. Installing a text file to
+.B /usr/lib/nvidia/alternate-install-available
+will alert nvidia-installer that an alternate installation option is available. The contents of
+.B /usr/lib/nvidia/alternate-install-present
+or
+.B /usr/lib/nvidia/alternate-install-available
+will be printed in a message informing the user of the presence/availability of the alternate driver installation, and asking the user whether to continue with the installation.
.SH EXAMPLES
.TP
.B nvidia\-installer \-\-latest
diff --git a/nvidia-installer.c b/nvidia-installer.c
index 8b2ddc1..cc3c752 100644
--- a/nvidia-installer.c
+++ b/nvidia-installer.c
@@ -146,6 +146,7 @@ static Options *load_default_options(void)
op->run_distro_scripts = TRUE;
op->no_kernel_module_source = FALSE;
op->dkms = FALSE;
+ op->check_for_alternate_installs = TRUE;
return op;
diff --git a/nvidia-installer.h b/nvidia-installer.h
index ee47562..afaea29 100644
--- a/nvidia-installer.h
+++ b/nvidia-installer.h
@@ -145,6 +145,7 @@ typedef struct __options {
int no_opengl_files;
int no_kernel_module_source;
int dkms;
+ int check_for_alternate_installs;
char *opengl_prefix;
char *opengl_libdir;
@@ -385,10 +386,7 @@ typedef struct __package {
#define PERM_MASK (S_IRWXU|S_IRWXG|S_IRWXO)
-#define PRECOMPILED_KERNEL_INTERFACE_FILENAME "precompiled-nv-linux.o"
-#define KERNEL_MODULE_CHECKSUM_FILENAME "nvidia-module-checksum"
-#define DETACHED_SIGNATURE_FILENAME "nvidia-detached-module-signature"
-
+#define PRECOMPILED_PACKAGE_FILENAME "nvidia-precompiled"
/*
* These are the default installation prefixes and the default
diff --git a/option_table.h b/option_table.h
index 8ada92c..897a054 100644
--- a/option_table.h
+++ b/option_table.h
@@ -92,6 +92,7 @@ enum {
MODULE_SIGNING_KEY_PATH_OPTION,
MODULE_SIGNING_HASH_OPTION,
MODULE_SIGNING_X509_HASH_OPTION,
+ NO_CHECK_FOR_ALTERNATE_INSTALLS_OPTION,
};
static const NVGetoptOption __options[] = {
@@ -604,6 +605,13 @@ static const NVGetoptOption __options[] = {
"name must be one of the message digest algorithms recognized by "
"the x509(1) command." },
+ { "no-check-for-alternate-installs", NO_CHECK_FOR_ALTERNATE_INSTALLS_OPTION,
+ 0, NULL,
+ "Maintainers of alternate driver installation methods can report the "
+ "presence and/or availability of an alternate driver installation to "
+ "nvidia-installer. Setting this option skips the check for alternate "
+ "driver installations." },
+
/* 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 ae1ab91..a5f8bfc 100644
--- a/precompiled.c
+++ b/precompiled.c
@@ -19,10 +19,6 @@
*
* precompiled.c - this source file contains functions for dealing
* with precompiled kernel interfaces.
- *
- * XXX portions of these functions are lifted from mkprecompiled (it
- * was much easier to duplicate them than to finesse the code to be
- * shared between the installer and mkprecompiled).
*/
@@ -42,32 +38,37 @@
#include "misc.h"
#include "crc.h"
-#define PRECOMPILED_CONSTANT_LENGTH (8 + 4 + 4 + 4 + 4)
+
+
+static int precompiled_read_fileinfo(Options *op, PrecompiledFileInfo *fileInfos,
+ int index, char *buf, int offset, int size);
/*
- * decode_uint32() - given an index into a buffer, read the next 4
- * bytes, and build a uint32.
+ * read_uint32() - given a buffer and an offset, read the next 4 bytes from
+ * the buffer at the given offset, build a uint32, and advance the offset.
*/
-static uint32 decode_uint32(char *buf)
+static uint32 read_uint32(const char *buf, int *offset)
{
uint32 ret = 0;
- ret += (((uint32) buf[3]) & 0xff);
+ ret += (((uint32) buf[*offset + 3]) & 0xff);
ret <<= 8;
- ret += (((uint32) buf[2]) & 0xff);
+ ret += (((uint32) buf[*offset + 2]) & 0xff);
ret <<= 8;
- ret += (((uint32) buf[1]) & 0xff);
+ ret += (((uint32) buf[*offset + 1]) & 0xff);
ret <<= 8;
- ret += (((uint32) buf[0]) & 0xff);
+ ret += (((uint32) buf[*offset]) & 0xff);
ret <<= 0;
+ *offset += sizeof(uint32);
+
return ret;
-} /* decode_uint32() */
+}
@@ -78,15 +79,15 @@ static uint32 decode_uint32(char *buf)
* mounted.
*/
-char *read_proc_version(Options *op)
+char *read_proc_version(Options *op, const char *proc_mount_point)
{
int fd, ret, len, version_len;
char *version, *c = NULL;
char *proc_verson_filename;
- len = strlen(op->proc_mount_point) + 9; /* strlen("/version") + 1 */
+ len = strlen(proc_mount_point) + 9; /* strlen("/version") + 1 */
proc_verson_filename = (char *) nvalloc(len);
- snprintf(proc_verson_filename, len, "%s/version", op->proc_mount_point);
+ snprintf(proc_verson_filename, len, "%s/version", proc_mount_point);
if ((fd = open(proc_verson_filename, O_RDONLY)) == -1) {
ui_warn(op, "Unable to open the file '%s' (%s).",
@@ -139,27 +140,26 @@ char *read_proc_version(Options *op)
/*
- * precompiled_unpack() - unpack the specified package. It's not
- * really an error if we can't open the file or if it's not the right
- * format, so just throw an expert-only log message.
+ * get_precompiled_info() - load the the specified package into a
+ * PrecompiledInfo record. It's not really an error if we can't open the file
+ * or if it's not the right format, so just throw an expert-only log message.
*/
-PrecompiledInfo *precompiled_unpack(Options *op,
- const char *filename,
- const char *output_filename,
- const char *real_proc_version_string,
- const char *package_version)
+PrecompiledInfo *get_precompiled_info(Options *op,
+ const char *filename,
+ const char *real_proc_version_string,
+ const char *package_version)
{
- int dst_fd, fd, offset, len = 0;
- char *buf, *dst;
- uint32 crc, val, size, linked_module_crc;
- char *version, *description, *proc_version_string,
- *detached_signature = NULL;
+ int fd, offset, num_files, i;
+ char *buf;
+ uint32 val, size;
+ char *version, *description, *proc_version_string;
struct stat stat_buf;
PrecompiledInfo *info = NULL;
+ PrecompiledFileInfo *fileInfos = NULL;
- fd = dst_fd = size = 0;
- buf = dst = description = proc_version_string = NULL;
+ fd = size = 0;
+ buf = description = proc_version_string = NULL;
/* open the file to be unpacked */
@@ -180,7 +180,7 @@ PrecompiledInfo *precompiled_unpack(Options *op,
/* check for a minimum length */
- if (size < PRECOMPILED_CONSTANT_LENGTH) {
+ if (size < PRECOMPILED_PKG_CONSTANT_LENGTH) {
ui_expert(op, "File '%s' appears to be too short.", filename);
goto done;
}
@@ -197,22 +197,25 @@ PrecompiledInfo *precompiled_unpack(Options *op,
/* check for the header */
- if (strncmp(buf + offset, "NVIDIA ", 8) != 0) {
+ if (strncmp(buf + offset, PRECOMPILED_PKG_HEADER, 8) != 0) {
ui_expert(op, "File '%s': unrecognized file format.", filename);
goto done;
}
offset += 8;
- /* read the crc */
+ /* check the package format version */
- crc = decode_uint32(buf + offset);
- offset += 4;
+ val = read_uint32(buf, &offset);
+ if (val != PRECOMPILED_PKG_VERSION) {
+ ui_expert(op, "Incompatible package format version %d: expected %d.",
+ val, PRECOMPILED_PKG_VERSION);
+ goto done;
+ }
/* read the version */
- val = decode_uint32(buf + offset);
- offset += 4;
- if ((val + PRECOMPILED_CONSTANT_LENGTH) > size) {
+ val = read_uint32(buf, &offset);
+ if ((val + PRECOMPILED_PKG_CONSTANT_LENGTH) > size) {
ui_expert(op, "Invalid file '%s' (bad version string length %d).",
filename, val);
goto done;
@@ -229,34 +232,28 @@ PrecompiledInfo *precompiled_unpack(Options *op,
/* check if this precompiled kernel interface is the right driver
version */
- if (strcmp(version, package_version) != 0) {
+ if (package_version && (strcmp(version, package_version) != 0)) {
goto done;
}
/* read the description */
- val = decode_uint32(buf + offset);
- offset += 4;
- if ((val + PRECOMPILED_CONSTANT_LENGTH) > size) {
+ val = read_uint32(buf, &offset);
+ if ((val + PRECOMPILED_PKG_CONSTANT_LENGTH) > size) {
ui_expert(op, "Invalid file '%s' (bad description string length %d).",
filename, val);
goto done;
}
- if (val > 0) {
- description = nvalloc(val+1);
- memcpy(description, buf + offset, val);
- description[val] = '\0';
- } else {
- description = NULL;
- }
+ description = nvalloc(val+1);
+ memcpy(description, buf + offset, val);
+ description[val] = '\0';
offset += val;
/* read the proc version string */
- val = decode_uint32(buf + offset);
- offset += 4;
- if ((val + PRECOMPILED_CONSTANT_LENGTH) > size) {
+ val = read_uint32(buf, &offset);
+ if ((val + PRECOMPILED_PKG_CONSTANT_LENGTH) > size) {
ui_expert(op, "Invalid file '%s' (bad version string length %d).",
filename, val);
goto done;
@@ -266,131 +263,686 @@ PrecompiledInfo *precompiled_unpack(Options *op,
offset += val;
proc_version_string[val] = '\0';
- /* if this interface appears to have been packaged by nvidia-installer,
- * get the linked module crc and path to the detached signature. */
-
- if (strstr(filename, PRECOMPILED_KERNEL_INTERFACE_FILENAME) ==
- strrchr(filename, '/') + 1) {
- char *suffix, *dirname, *tmp, *crc_file_path;
-
- dirname = nvstrdup(filename);
- tmp = strrchr(dirname, '/');
- *tmp = '\0';
-
- suffix = nvstrdup(strrchr(filename, '/') + 1 +
- strlen(PRECOMPILED_KERNEL_INTERFACE_FILENAME));
-
- detached_signature = nvstrcat(dirname, "/", DETACHED_SIGNATURE_FILENAME,
- suffix, NULL);
- crc_file_path = nvstrcat(dirname, "/", KERNEL_MODULE_CHECKSUM_FILENAME,
- suffix, NULL);
-
- if (access(detached_signature, F_OK | R_OK) == 0 &&
- access(crc_file_path, F_OK | R_OK) == 0) {
- FILE *crc_file;
-
- crc_file = fopen(crc_file_path, "r");
- if (crc_file) {
- int items_read = fread(&linked_module_crc,
- sizeof(linked_module_crc), 1, crc_file);
- if (items_read != 1) {
- ui_warn(op, "A checksum file for a linked kernel module "
- "was found, but reading the checksum failed.");
- detached_signature = NULL;
- }
- fclose(crc_file);
- }
- } else {
- detached_signature = NULL;
- }
- }
-
/* check if the running kernel matches */
- if (strcmp(real_proc_version_string, proc_version_string) != 0) {
+ if (real_proc_version_string &&
+ (strcmp(real_proc_version_string, proc_version_string) != 0)) {
goto done;
}
ui_log(op, "A precompiled kernel interface for kernel '%s' has been "
"found here: %s.", description, filename);
-
- /* extract kernel interface module */
-
- len = size - offset;
- if ((dst_fd = open(output_filename, O_CREAT | O_RDWR | O_TRUNC,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) {
- ui_error(op, "Unable to open output file '%s' (%s).", output_filename,
- strerror(errno));
- goto done;
- }
-
- /* set the output file length */
+ num_files = read_uint32(buf, &offset);
+ fileInfos = nvalloc(num_files * sizeof(PrecompiledFileInfo));
+ for (i = 0; i < num_files; i++) {
+ int ret;
+ ret = precompiled_read_fileinfo(op, fileInfos, i, buf, offset, size);
- if ((lseek(dst_fd, len - 1, SEEK_SET) == -1) ||
- (write(dst_fd, "", 1) == -1)) {
- ui_error(op, "Unable to set output file '%s' length %d (%s).\n",
- output_filename, len, strerror(errno));
- goto done;
+ if (ret > 0) {
+ offset += ret;
+ } else {
+ ui_log(op, "An error occurred while trying to parse '%s'.",
+ filename);
+ goto done;
+ }
}
- /* mmap the dst */
-
- dst = mmap(0, len, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, dst_fd, 0);
- if (dst == (void *) -1) {
- ui_error(op, "Unable to mmap output file %s (%s).\n",
- output_filename, strerror(errno));
- goto done;
- }
-
- /* copy */
-
- memcpy(dst, buf + offset, len);
-
/*
* now that we can no longer fail, allocate and initialize the
* PrecompiledInfo structure
*/
info = (PrecompiledInfo *) nvalloc(sizeof(PrecompiledInfo));
- info->crc = crc;
+ info->package_size = size;
info->version = version;
info->proc_version_string = proc_version_string;
info->description = description;
- info->detached_signature = detached_signature;
- info->linked_module_crc = linked_module_crc;
+ info->num_files = num_files;
+ info->files = fileInfos;
/*
- * XXX so that the proc version, description, and detached_signature strings
- * aren't freed below
+ * XXX so that the proc version and description strings, and the
+ * PrecompiledFileInfo array aren't freed below
*/
-
- proc_version_string = description = detached_signature = NULL;
+
+ proc_version_string = description = NULL;
+ fileInfos = NULL;
done:
-
+
/* cleanup whatever needs cleaning up */
- if (dst) munmap(dst, len);
if (buf) munmap(buf, size);
if (fd > 0) close(fd);
- if (dst_fd > 0) close(dst_fd);
if (description) free(description);
if (proc_version_string) free(proc_version_string);
- if (detached_signature) free(detached_signature);
+ if (fileInfos) free(fileInfos);
return info;
-
-} /* mkprecompiled_unpack() */
+}
+
+
+/*
+ * precompiled_file_unpack() - Unpack an individual precompiled file to the
+ * specified output directory.
+ */
+
+int precompiled_file_unpack(Options *op, const PrecompiledFileInfo *fileInfo,
+ const char *output_directory)
+{
+ int ret = FALSE, dst_fd = 0;
+ char *dst_path, *dst = NULL;
+
+ dst_path = nvstrcat(output_directory, "/", fileInfo->name, NULL);
+
+ /* extract file */
+
+ if ((dst_fd = open(dst_path, O_CREAT | O_RDWR | O_TRUNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) {
+ ui_error(op, "Unable to open output file '%s' (%s).", dst_path,
+ strerror(errno));
+ goto done;
+ }
+
+ /* set the output file length */
+
+ if ((lseek(dst_fd, fileInfo->size - 1, SEEK_SET) == -1) ||
+ (write(dst_fd, "", 1) == -1)) {
+ ui_error(op, "Unable to set output file '%s' length %d (%s).\n",
+ dst_path, fileInfo->size, strerror(errno));
+ goto done;
+ }
+
+ /* mmap the dst */
+
+ dst = mmap(0, fileInfo->size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, dst_fd, 0);
+ if (dst == (void *) -1) {
+ ui_error(op, "Unable to mmap output file %s (%s).\n",
+ dst_path, strerror(errno));
+ goto done;
+ }
+
+ /* copy */
+
+ memcpy(dst, fileInfo->data, fileInfo->size);
+
+ ret = TRUE;
+
+done:
+
+ /* cleanup whatever needs cleaning up */
+
+ nvfree(dst_path);
+ if (dst) munmap(dst, fileInfo->size);
+ if (dst_fd > 0) close(dst_fd);
+
+ return ret;
+}
+
+
+/* precompiled_unpack() - unpack all of the files in a PrecompiledInfo into
+ * the given destination directory */
+int precompiled_unpack(Options *op, const PrecompiledInfo *info,
+ const char *output_directory)
+{
+ int i;
+
+ if (!info) {
+ return FALSE;
+ }
+
+ for (i = 0; i < info->num_files; i++) {
+ if (!precompiled_file_unpack(op, &(info->files[i]), output_directory)) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+
+/*
+ * encode_uint32() - given a uint32, a data buffer, and an offset into the data
+ * buffer, write the integer to the data buffer and advance the offset by the
+ * number of bytes written.
+ */
+
+static void encode_uint32(uint32 val, uint8 *data, int *offset)
+{
+ data[*offset + 0] = ((val >> 0) & 0xff);
+ data[*offset + 1] = ((val >> 8) & 0xff);
+ data[*offset + 2] = ((val >> 16) & 0xff);
+ data[*offset + 3] = ((val >> 24) & 0xff);
+
+ *offset += sizeof(uint32);
+}
+
+
+/*
+ * precompiled_pack() - pack the specified precompiled kernel interface
+ * file, prepended with a header, the CRC the driver version, a description
+ * string, and the proc version string.
+ */
+
+int precompiled_pack(const PrecompiledInfo *info, const char *package_filename)
+{
+ int fd, offset;
+ uint8 *out;
+ int version_len, description_len, proc_version_len;
+ int total_len, files_len, i;
+
+ /*
+ * get the lengths of the description, the proc version string,
+ * and the files to be packaged along with the associated metadata.
+ */
+
+ version_len = strlen(info->version);
+ description_len = strlen(info->description);
+ proc_version_len = strlen(info->proc_version_string);
+
+ for (files_len = i = 0; i < info->num_files; i++) {
+ files_len += PRECOMPILED_FILE_CONSTANT_LENGTH +
+ strlen(info->files[i].name) +
+ strlen(info->files[i].linked_module_name) +
+ strlen(info->files[i].core_object_name) +
+ info->files[i].size +
+ info->files[i].signature_size;
+ }
+
+ total_len = PRECOMPILED_PKG_CONSTANT_LENGTH +
+ version_len + description_len + proc_version_len + files_len;
+
+ /* open the output file for writing */
+
+ fd = nv_open(package_filename, O_CREAT|O_RDWR|O_TRUNC,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+
+ /* set the output file length */
+
+ nv_set_file_length(package_filename, fd, total_len);
+
+ /* map the output file */
+
+ out = nv_mmap(package_filename, total_len, PROT_READ|PROT_WRITE,
+ MAP_FILE|MAP_SHARED, fd);
+ offset = 0;
+
+ /* write the header */
+
+ memcpy(&(out[0]), PRECOMPILED_PKG_HEADER, 8);
+ offset += 8;
+
+ /* write the package version */
+
+ encode_uint32(PRECOMPILED_PKG_VERSION, out, &offset);
+
+ /* write the version */
+
+ encode_uint32(version_len, out, &offset);
+
+ if (version_len) {
+ memcpy(&(out[offset]), info->version, version_len);
+ offset += version_len;
+ }
+
+ /* write the description */
+
+ encode_uint32(description_len, out, &offset);
+
+ if (description_len) {
+ memcpy(&(out[offset]), info->description, description_len);
+ offset += description_len;
+ }
+
+ /* write the proc version string */
+
+ encode_uint32(proc_version_len, out, &offset);
+
+ memcpy(&(out[offset]), info->proc_version_string, proc_version_len);
+ offset += proc_version_len;
+
+ /* write the number of files */
+
+ encode_uint32(info->num_files, out, &offset);
+
+ /* write the files */
+ for (i = 0; i < info->num_files; i++) {
+ PrecompiledFileInfo *file = &(info->files[i]);
+ uint32 name_len = strlen(file->name);
+ uint32 linked_module_name_len = strlen(file->linked_module_name);
+ uint32 core_object_name_len = strlen(file->core_object_name);
+
+ /* file header */
+ memcpy(&(out[offset]), PRECOMPILED_FILE_HEADER, 4);
+ offset += 4;
+
+ /* file sequence number */
+ encode_uint32(i, out, &offset);
+
+ /* file type and attributes*/
+ encode_uint32(file->type, out, &offset);
+ encode_uint32(file->attributes, out, &offset);
+
+ /* file name */
+ encode_uint32(name_len, out, &offset);
+ memcpy(&(out[offset]), file->name, name_len);
+ offset += name_len;
+
+ /* linked module name */
+ encode_uint32(linked_module_name_len, out, &offset);
+ memcpy(&(out[offset]), file->linked_module_name, linked_module_name_len);
+ offset += linked_module_name_len;
+
+ /* core object name */
+ encode_uint32(core_object_name_len, out, &offset);
+ memcpy(&(out[offset]), file->core_object_name, core_object_name_len);
+ offset += core_object_name_len;
+
+ /* crc */
+ encode_uint32(file->crc, out, &offset);
+
+ /* file */
+ encode_uint32(file->size, out, &offset);
+ memcpy(&(out[offset]), file->data, file->size);
+ offset += file->size;
+
+ /* redundant crc */
+ encode_uint32(file->crc, out, &offset);
+
+ /* linked module crc */
+ encode_uint32(file->linked_module_crc, out, &offset);
+
+ /* detached signature */
+ encode_uint32(file->signature_size, out, &offset);
+ if (file->signature_size) {
+ memcpy(&(out[offset]), file->signature, file->signature_size);
+ offset += file->signature_size;
+ }
+
+ /* redundant file sequence number */
+ encode_uint32(i, out, &offset);
+
+ /* file footer */
+ memcpy(&(out[offset]), PRECOMPILED_FILE_FOOTER, 4);
+ offset += 4;
+ }
+
+ /* unmap package */
+
+ munmap(out, total_len);
+
+ close(fd);
+
+ return TRUE;
+
+}
+
+
+
/*
* free_precompiled() - free any malloced strings stored in a PrecompiledInfo,
* then free the PrecompiledInfo.
*/
void free_precompiled(PrecompiledInfo *info)
{
+ int i;
+
+ if (!info) {
+ return;
+ }
+
nvfree(info->description);
nvfree(info->proc_version_string);
- nvfree(info->detached_signature);
+ nvfree(info->version);
+
+ for (i = 0; i < info->num_files; i++) {
+ free_precompiled_file_data(info->files[i]);
+ }
+ nvfree(info->files);
+
nvfree(info);
}
+
+
+
+void free_precompiled_file_data(PrecompiledFileInfo fileInfo)
+{
+ nvfree(fileInfo.name);
+ nvfree(fileInfo.linked_module_name);
+ nvfree(fileInfo.data);
+ nvfree(fileInfo.signature);
+}
+
+
+
+/*
+ * precompiled_read_file() - attempt to open the file at the specified path and
+ * populate a PrecompiledFileInfo record with its contents and the appropriate
+ * metadata. Return a pointer to a newly allocated PrecompiledFile record on
+ * success, or NULL on failure.
+ */
+
+static int precompiled_read_file(PrecompiledFileInfo *fileInfo,
+ const char *filename,
+ const char *linked_module_name,
+ const char *core_object_name, uint32 type)
+{
+ int fd;
+ struct stat st;
+ int success = FALSE, ret;
+
+ fd = open(filename, O_RDONLY);
+ if (fd == -1) {
+ goto done;
+ }
+
+ if (fstat(fd, &st) != 0) {
+ goto done;
+ }
+
+ fileInfo->size = st.st_size;
+ fileInfo->data = nvalloc(fileInfo->size);
+
+ ret = read(fd, fileInfo->data, fileInfo->size);
+
+ if (ret != fileInfo->size) {
+ goto done;
+ }
+
+ fileInfo->type = type;
+ fileInfo->name = nv_basename(filename);
+ fileInfo->linked_module_name = nvstrdup(linked_module_name);
+ fileInfo->core_object_name = nvstrdup(core_object_name);
+ fileInfo->crc = compute_crc(NULL, filename);
+
+ success = TRUE;
+
+done:
+ close(fd);
+ return success;
+}
+
+
+int precompiled_read_interface(PrecompiledFileInfo *fileInfo,
+ const char *filename,
+ const char *linked_module_name,
+ const char *core_object_name)
+{
+ return precompiled_read_file(fileInfo, filename, linked_module_name,
+ core_object_name,
+ PRECOMPILED_FILE_TYPE_INTERFACE);
+}
+
+int precompiled_read_module(PrecompiledFileInfo *fileInfo, const char *filename)
+{
+ return precompiled_read_file(fileInfo, filename, "", "",
+ PRECOMPILED_FILE_TYPE_MODULE);
+}
+
+
+
+/*
+ * precompiled_read_fileinfo() - Read a PrecompiledFileInfo record from a binary
+ * precompiled file package.
+ *
+ * Parameters:
+ * op: A pointer to the options structure, used for ui_* functions
+ * fileInfos: A PrecompiledFileInfo array, where the decoded file data from
+ * the binary package will be stored
+ * index: The index into fileInfos where the decoded file data will be
+ * stored. Used to verify that the file number recorded in the
+ * package is valid.
+ * buf: The raw buffer containing the binary package data. This should
+ * point to the beginning of the package file.
+ * offset: The offset into buf where the file data to be read begins.
+ * size: The size of the package data buffer. This is used for bounds
+ * checking, to make sure that a reading a length specified in the
+ * won't go past the end of the package file.
+ *
+ * Return value:
+ * The number of bytes read from the package file on success, or -1 on error.
+ */
+
+static int precompiled_read_fileinfo(Options *op, PrecompiledFileInfo *fileInfos,
+ int index, char *buf, int offset, int size)
+{
+ PrecompiledFileInfo *fileInfo = fileInfos + index;
+ uint32 val;
+ int oldoffset = offset;
+
+ if (size - offset < PRECOMPILED_FILE_CONSTANT_LENGTH) {
+ return -1;
+ }
+
+ if (strncmp(buf + offset, PRECOMPILED_FILE_HEADER, 4) != 0) {
+ ui_log(op, "Unrecognized header for packaged file.");
+ return -1;
+ }
+ offset += 4;
+
+ val = read_uint32(buf, &offset);
+ if (val != index) {
+ ui_log(op, "Invalid file index %d; expected %d.", val, index);
+ return -1;
+ }
+
+ fileInfo->type = read_uint32(buf, &offset);
+ fileInfo->attributes = read_uint32(buf, &offset);
+
+ val = read_uint32(buf, &offset);
+ if (offset + val > size) {
+ ui_log(op, "Bad filename length.");
+ return -1;
+ }
+
+ fileInfo->name = nvalloc(val + 1);
+ memcpy(fileInfo->name, buf + offset, val);
+ offset += val;
+
+ val = read_uint32(buf, &offset);
+ if (offset + val > size) {
+ ui_log(op, "Bad linked module name length.");
+ return -1;
+ }
+
+ fileInfo->linked_module_name = nvalloc(val + 1);
+ memcpy(fileInfo->linked_module_name, buf + offset, val);
+ offset += val;
+
+ val = read_uint32(buf, &offset);
+ if (offset + val > size) {
+ ui_log(op, "Bad core object file name length.");
+ return -1;
+ }
+
+ fileInfo->core_object_name = nvalloc(val + 1);
+ memcpy(fileInfo->core_object_name, buf + offset, val);
+ offset += val;
+
+ fileInfo->crc = read_uint32(buf, &offset);
+
+ fileInfo->size = read_uint32(buf, &offset);
+ if (offset + fileInfo->size > size) {
+ ui_log(op, "Bad file length.");
+ return -1;
+ }
+
+ fileInfo->data = nvalloc(fileInfo->size);
+ memcpy(fileInfo->data, buf + offset, fileInfo->size);
+ offset += fileInfo->size;
+
+ val = read_uint32(buf, &offset);
+ if (val != fileInfo->crc) {
+ ui_log(op, "The redundant stored CRC values %" PRIu32 " and %" PRIu32
+ " disagree with each other; the file may be corrupted.",
+ fileInfo->crc, val);
+ return -1;
+ }
+
+ val = compute_crc_from_buffer(fileInfo->data, fileInfo->size);
+ if (val != fileInfo->crc) {
+ ui_log(op, "The CRC for the file '%s' (%" PRIu32 ") does not match the "
+ "expected value (%" PRIu32 ").", fileInfo->name, val,
+ fileInfo->crc);
+ }
+
+ fileInfo->linked_module_crc = read_uint32(buf, &offset);
+
+ fileInfo->signature_size = read_uint32(buf, &offset);
+ if(fileInfo->signature_size) {
+ if (offset + fileInfo->signature_size > size) {
+ ui_log(op, "Bad signature size");
+ return -1;
+ }
+ fileInfo->signature = nvalloc(fileInfo->signature_size);
+ memcpy(fileInfo->signature, buf + offset, fileInfo->signature_size);
+ offset += fileInfo->signature_size;
+ }
+
+ val = read_uint32(buf, &offset);
+ if (val != index) {
+ ui_log(op, "Invalid file index %d; expected %d.", val, index);
+ return -1;
+ }
+
+ if (strncmp(buf + offset, PRECOMPILED_FILE_FOOTER, 4) != 0) {
+ ui_log(op, "Unrecognized footer for packaged file.");
+ return -1;
+ }
+ offset += 4;
+
+ return offset - oldoffset;
+}
+
+
+/*
+ * precompiled_find_file() - search for a file with the given name within the
+ * given PrecompiledInfo record, and return a pointer to it if found, or NULL
+ * if not found.
+ */
+
+PrecompiledFileInfo *precompiled_find_file(const PrecompiledInfo *info,
+ const char *file)
+{
+ int i;
+
+ for (i = 0; i < info->num_files; i++) {
+ if (strcmp(file, info->files[i].name) == 0) {
+ return info->files + i;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * precompiled_append_files() - append the given PrecompiledFileInfo array to
+ * the already existing files in the given PrecompiledInfo.
+ */
+
+void precompiled_append_files(PrecompiledInfo *info, PrecompiledFileInfo *files,
+ int num_files)
+{
+ info->files = nvrealloc(info->files, (info->num_files + num_files) *
+ sizeof(PrecompiledFileInfo));
+ memcpy(info->files + info->num_files, files,
+ num_files * sizeof(PrecompiledFileInfo));
+ info->num_files += num_files;
+}
+
+/*
+ * precompiled_file_type_name() - return a pointer to a human-readable string
+ * naming a file type. The string should not be freed.
+ */
+const char *precompiled_file_type_name(uint32 file_type)
+{
+ static const char *file_type_names[] = {
+ "precompiled kernel interface",
+ "precompiled kernel module",
+ };
+
+ if (file_type >= ARRAY_LEN(file_type_names)) {
+ return "unknown file type";
+ }
+
+ return file_type_names[file_type];
+}
+
+/*
+ * precompiled_file_attribute_names() - return a NULL-terminated list of
+ * human-readable strings naming the attributes in the given file attribute
+ * mask. The list should be freed when no longer used, but the constituent
+ * strings should not be freed.
+ */
+const char **precompiled_file_attribute_names(uint32 attribute_mask)
+{
+ const char **ret;
+ int i, attr = 0;
+
+ static const char *file_attribute_names[] = {
+ "detached signature",
+ "linked module crc",
+ "embedded signature",
+ };
+
+ ret = nvalloc((ARRAY_LEN(file_attribute_names) + 1) * sizeof(char *));
+
+ for (i = 0; i < 32; i++) {
+ if (attribute_mask & (1 << i)) {
+ ret[attr++] = file_attribute_names[i];
+ }
+ }
+ ret[attr] = NULL;
+
+ return ret;
+}
+
+
+
+/*
+ * byte_tail() - copy from infile, starting at the specified byte offset, and
+ * going until the end of infile to a newly allocated buffer, a pointer to
+ * which is stored at location given by the caller. Returns the size of the new
+ * buffer on success; returns 0 and sets the caller pointer to NULL on failure.
+ * This is needed because `tail -c` is unreliable in some implementations.
+ */
+int byte_tail(const char *infile, int start, char **buf)
+{
+ FILE *in = NULL;
+ int ret, end, size = 0;
+
+ in = fopen(infile, "r");
+
+ if (!in) {
+ goto done;
+ }
+
+ ret = fseek(in, 0, SEEK_END);
+ if (ret != 0) {
+ goto done;
+ }
+ end = ftell(in);
+
+ ret = fseek(in, start, SEEK_SET);
+ if (ret != 0) {
+ goto done;
+ }
+
+ size = end - start;
+ *buf = nvalloc(size);
+
+ ret = (fread(*buf, 1, size + 1, in));
+ if (ret != size || ferror(in) || !feof(in)) {
+ nvfree(*buf);
+ *buf = NULL;
+ goto done;
+ }
+
+done:
+ fclose(in);
+ return size;
+}
diff --git a/precompiled.h b/precompiled.h
index 999208b..7d727a6 100644
--- a/precompiled.h
+++ b/precompiled.h
@@ -2,7 +2,7 @@
* nvidia-installer: A tool for installing NVIDIA software packages on
* Unix and Linux systems.
*
- * Copyright (C) 2003 NVIDIA Corporation
+ * Copyright (C) 2003-2013 NVIDIA Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -16,35 +16,178 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses>.
*
+ * precompiled.h: common definitions for mkprecompiled and nvidia-installer's
+ * precompiled kernel interface/module package format
*
- * precompiled.h
+ * The format of a precompiled kernel interface package is:
+ *
+ * the first 8 bytes are: "\aNVIDIA\a"
+ *
+ * the next 4 bytes (unsigned) are: version number of the package format
+ *
+ * the next 4 bytes (unsigned) are: the length of the version string (v)
+ *
+ * the next v bytes are the version string
+ *
+ * the next 4 bytes (unsigned) are: the length of the description (d)
+ *
+ * the next d bytes are the description
+ *
+ * the next 4 bytes (unsigned) are: the length of the proc version string (p)
+ *
+ * the next p bytes are the proc version string
+ *
+ * the next 4 bytes (unsigned) are: the number of files in this package (f)
+ *
+ * for each of the f packaged files:
+ *
+ * the first 4 bytes are: "FILE"
+ *
+ * the next 4 bytes (unsigned) are: the 0-indexed sequence number of this file
+ *
+ * the next 4 bytes (unsigned) are the file type:
+ * 0: precompiled interface
+ * 1: precompiled kernel module
+ *
+ * the next 4 bytes are an attribute mask:
+ * 1: has detached signature
+ * 2: has linked module CRC
+ * 4: has embedded signature
+ *
+ * the next 4 bytes (unsigned) are: length of the file name (n)
+ *
+ * the next n bytes are the file name
+ *
+ * the next 4 bytes (unsigned) are: length of the linked module name (m)
+ *
+ * the next m bytes are the linked module name (for kernel interfaces only)
+ *
+ * the next 4 bytes (unsigned) are: length of the core object file name (o)
+ *
+ * the next o bytes are the core object file name (for kernel interfaces only)
+ *
+ * the next 4 bytes (unsigned) are: CRC of the packaged file
+ *
+ * the next 4 bytes (unsigned) are: size of the packaged file (l)
+ *
+ * the next l bytes is the packaged file
+ *
+ * the next 4 bytes (unsigned) are: CRC of the packaged file, again
+ *
+ * the next 4 bytes (unsigned) are: CRC of linked module, when appropriate;
+ * undefined if "has linked module CRC" attribute is not set
+ *
+ * the next 4 bytes (unsigned) are: length of detached signature (s), when
+ * appropriate; 0 if "has detached signature" attribute is not set
+ *
+ * the next (s) bytes are: detached signature
+ *
+ * the next 4 bytes (unsigned) are: the 0-indexed sequence number of this file
+ *
+ * the next 4 bytes are: "END."
*/
#ifndef __NVIDIA_INSTALLER_PRECOMPILED_H__
#define __NVIDIA_INSTALLER_PRECOMPILED_H__
-#define OUTPUT_FILENAME "nv-linux.o"
+#define PRECOMPILED_PKG_CONSTANT_LENGTH (8 + /* precompiled package header */ \
+ 4 + /* package format version */ \
+ 4 + /* driver version string length */ \
+ 4 + /* description string length */ \
+ 4 + /* proc version string length */ \
+ 4) /* number of files */
+
+#define PRECOMPILED_PKG_HEADER "\aNVIDIA\a"
+
+#define PRECOMPILED_PKG_VERSION 1
+
+#define PRECOMPILED_FILE_CONSTANT_LENGTH (4 + /* precompiled file header */ \
+ 4 + /* file serial number */ \
+ 4 + /* file type */ \
+ 4 + /* attributes mask */ \
+ 4 + /* file name length */ \
+ 4 + /* linked module name length */ \
+ 4 + /* core object name length */ \
+ 4 + /* file crc */ \
+ 4 + /* file size */ \
+ 4 + /* redundant file crc */ \
+ 4 + /* linked module crc */ \
+ 4 + /* detached signature length */ \
+ 4 + /* redundant file serial number */ \
+ 4) /* precompiled file footer*/
+
+#define PRECOMPILED_FILE_HEADER "FILE"
+#define PRECOMPILED_FILE_FOOTER "END."
+
+enum {
+ PRECOMPILED_FILE_TYPE_INTERFACE = 0,
+ PRECOMPILED_FILE_TYPE_MODULE,
+};
-typedef struct {
-
+enum {
+ PRECOMPILED_FILE_HAS_DETACHED_SIGNATURE = 0,
+ PRECOMPILED_FILE_HAS_LINKED_MODULE_CRC,
+ PRECOMPILED_FILE_HAS_EMBEDDED_SIGNATURE,
+};
+
+#define PRECOMPILED_ATTR(attr) (1 << PRECOMPILED_FILE_HAS_##attr)
+
+typedef struct __precompiled_file_info {
+ uint32 type;
+ uint32 attributes;
+ char *name;
+ char *linked_module_name;
+ char *core_object_name;
uint32 crc;
+ uint32 size;
+ uint8 *data;
+ uint32 linked_module_crc;
+ uint32 signature_size;
+ char *signature;
+} PrecompiledFileInfo;
+
+typedef struct __precompiled_info {
+
+ uint32 package_size;
char *version;
char *proc_version_string;
char *description;
- char *detached_signature;
- uint32 linked_module_crc;
+ int num_files;
+ PrecompiledFileInfo *files;
} PrecompiledInfo;
-char *read_proc_version(Options *op);
+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);
+
+PrecompiledFileInfo *precompiled_find_file(const PrecompiledInfo *info,
+ const char *file);
+
+int precompiled_file_unpack(Options *op, const PrecompiledFileInfo *fileInfo,
+ const char *output_directory);
+int precompiled_unpack(Options *op, const PrecompiledInfo *info,
+ const char *output_filename);
+
+int precompiled_pack(const PrecompiledInfo *info, const char *package_filename);
-PrecompiledInfo *precompiled_unpack(Options *op,
- const char *filename,
- const char *output_filename,
- const char *real_proc_version_string,
- const char *package_version);
void free_precompiled(PrecompiledInfo *info);
+void free_precompiled_file_data(PrecompiledFileInfo fileInfo);
+int precompiled_read_interface(PrecompiledFileInfo *fileInfo,
+ const char *filename,
+ const char *linked_module_name,
+ const char *core_object_name);
+int precompiled_read_module(PrecompiledFileInfo *fileInfo, const char *filename);
+void precompiled_append_files(PrecompiledInfo *info, PrecompiledFileInfo *files,
+ int num_files);
+
+const char *precompiled_file_type_name(uint32 file_type);
+const char **precompiled_file_attribute_names(uint32 attribute_mask);
+int byte_tail(const char *infile, int start, char **buf);
#endif /* __NVIDIA_INSTALLER_PRECOMPILED_H__ */
diff --git a/version.mk b/version.mk
index 47298b6..a8b6fa4 100644
--- a/version.mk
+++ b/version.mk
@@ -1 +1 @@
-NVIDIA_VERSION = 319.32
+NVIDIA_VERSION = 325.08