This commit is contained in:
Aaron Plattner
2013-07-01 08:54:54 -07:00
parent 45f2c99ed8
commit bae15338d0
21 changed files with 2010 additions and 1059 deletions

View File

@@ -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

View File

@@ -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 }
};

View File

@@ -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;
}

View File

@@ -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__ */

30
crc.c
View File

@@ -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;

1
crc.h
View File

@@ -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__ */

105
files.c
View File

@@ -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 PrecompiledInfo struct */
info = nvalloc(sizeof(PrecompiledInfo));
outfile = nvstrcat(p->precompiled_kernel_interface_directory, "/",
PRECOMPILED_PACKAGE_FILENAME, "-", p->version,
".", time_str, NULL);
info->version = nvstrdup(p->version);
info->proc_version_string = proc_version_string;
info->description = descr;
info->num_files = num_files;
info->files = files;
ret = precompiled_pack(info, outfile);
nvfree(outfile);
free_precompiled(info);
/* 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 */
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);
if (ret) {
return TRUE;
}
else {
/* XXX precompiled_pack() never fails */
ui_error(op, "Unable to package precompiled kernel interface.");
return FALSE;
}
nvfree(file);
file = nvstrcat(p->kernel_module_build_directory, "/",
KERNEL_MODULE_CHECKSUM_FILENAME, NULL);
if (access(file, R_OK) == 0) {
newfile = nvstrcat(p->precompiled_kernel_interface_directory, "/",
KERNEL_MODULE_CHECKSUM_FILENAME, suffix, NULL);
rename(file, newfile);
nvfree(newfile);
}
nvfree(file);
/* 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);
}
nvfree(result);
if (ret == 0) return TRUE;
else return FALSE;
} /* pack_kernel_interface() */
}

View File

@@ -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);

View File

@@ -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);

527
kernel.c
View File

@@ -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);
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);
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 */
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;
}
}
ui_status_end(op, "done.");
failed:
ui_log(op, "Kernel module interface compilation complete.");
/* copy the kernel interface from the tmpdir back to the srcdir */
dstfile = nvstrcat(p->kernel_module_build_directory, "/",
PRECOMPILED_KERNEL_INTERFACE_FILENAME, NULL);
if (!copy_file(op, kernel_interface, dstfile, 0644)) goto failed;
if (op->module_signing_secret_key && op->module_signing_public_key) {
ret = create_detached_signature(op, p, tmpdir);
} else {
ret = TRUE;
if (files_packaged == 0) {
nvfree(*fileInfos);
*fileInfos = NULL;
}
failed:
remove_directory(op, tmpdir);
if (tmpdir) nvfree(tmpdir);
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);
}
/*
@@ -1806,6 +1756,74 @@ static char *default_kernel_source_path(Options *op)
} /* default_kernel_source_path() */
/*
* 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
@@ -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;
@@ -2147,6 +2171,35 @@ 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.
@@ -2154,7 +2207,6 @@ static int xen_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)
{
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) {

View File

@@ -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*);

98
misc.c
View File

@@ -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

1
misc.h
View File

@@ -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);

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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 },

View File

@@ -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;
}

View File

@@ -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 */
typedef struct {
#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,
};
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__ */

View File

@@ -1 +1 @@
NVIDIA_VERSION = 319.32
NVIDIA_VERSION = 325.08