520.56.06

This commit is contained in:
Aaron Plattner
2022-10-12 07:40:57 -07:00
parent 9aeab72985
commit 6ada527214
17 changed files with 807 additions and 290 deletions

View File

@@ -678,7 +678,7 @@ static int do_uninstall(Options *op, const char *version,
/* Remove any installed DKMS modules */
if (dkms_module_installed(op, version)) {
if (dkms_module_installed(op, version, NULL)) {
ui_log(op, "DKMS module detected; removing...");
if (!dkms_remove_module(op, version)) {
ui_warn(op, "Failed to remove installed DKMS module!");
@@ -844,11 +844,11 @@ static int do_uninstall(Options *op, const char *version,
if (!op->skip_depmod) {
char *cmd = nvstrcat(op->utils[DEPMOD], " -a ", op->kernel_name, NULL);
status |= run_command(op, cmd, NULL, FALSE, 0, FALSE);
status |= run_command(op, cmd, NULL, FALSE, NULL, FALSE);
nvfree(cmd);
}
status |= run_command(op, op->utils[LDCONFIG], NULL, FALSE, 0, FALSE);
status |= run_command(op, op->utils[LDCONFIG], NULL, FALSE, NULL, FALSE);
if (status == 0) {
ui_log(op, "done.");
@@ -867,7 +867,7 @@ static int do_uninstall(Options *op, const char *version,
char *cmd = nvstrcat(op->utils[SYSTEMCTL], " daemon-reload", NULL);
ui_log(op, "Running `%s`:", cmd);
status = run_command(op, cmd, NULL, FALSE, 0, FALSE);
status = run_command(op, cmd, NULL, FALSE, NULL, FALSE);
nvfree(cmd);
if (status == 0) {
@@ -1448,7 +1448,7 @@ static int check_skip_depmod_support(Options *op, const char *uninstaller)
char *cmd = nvstrcat(uninstaller, " -A | ", op->utils[GREP],
" -q '^ \\+--skip-depmod$'", NULL);
int ret = run_command(op, cmd, NULL, FALSE, 0, FALSE);
int ret = run_command(op, cmd, NULL, FALSE, NULL, FALSE);
nvfree(cmd);
@@ -1473,42 +1473,56 @@ int run_existing_uninstaller(Options *op)
int skip_depmod = !op->no_kernel_modules;
if (uninstaller) {
char *uninstall_log_dir, *uninstall_log_file, *uninstall_log_path;
char *uninstall_cmd = NULL;
char *data = NULL;
int ret;
skip_depmod = skip_depmod && check_skip_depmod_support(op, uninstaller);
/*
* Use DEFAULT_UNINSTALL_LOG_FILE_NAME as the name for the uninstall
* log file, in the same directory as op->log_file_name, be it the
* default location or a custom one.
*/
uninstall_log_dir = nv_dirname(op->log_file_name);
uninstall_log_file = nv_basename(DEFAULT_UNINSTALL_LOG_FILE_NAME);
uninstall_log_path = nvdircat(uninstall_log_dir, uninstall_log_file,
NULL);
nvfree(uninstall_log_dir);
nvfree(uninstall_log_file);
/* Run the uninstaller non-interactively, and explicitly log to the
* uninstall log location: older installers may not do so implicitly. */
uninstall_cmd = nvstrcat(uninstaller, " -s --log-file-name="
DEFAULT_UNINSTALL_LOG_FILE_NAME,
uninstall_cmd = nvstrcat(uninstaller, " -s --log-file-name=",
uninstall_log_path,
skip_depmod ? " --skip-depmod" : NULL,
NULL);
ui_log(op, "Uninstalling the previous installation with %s.",
uninstaller);
ret = run_command(op, uninstall_cmd, &data, FALSE, 0, TRUE);
ret = run_command(op, uninstall_cmd, &data, FALSE, NULL, TRUE);
nvfree(uninstall_cmd);
/* if nvidia-uninstall succeeded, return early; otherwise, fall back to
* uninstalling via the backup log file. */
if (ret == 0) {
nvfree(uninstaller);
nvfree(data);
return TRUE;
} else {
if (ret != 0) {
ui_log(op, "%s failed; see %s for more details.", uninstaller,
DEFAULT_UNINSTALL_LOG_FILE_NAME);
uninstall_log_path);
if (data && strlen(data)) {
ui_log(op, "The output from %s was:\n%s", uninstaller, data);
}
nvfree(data);
}
nvfree(data);
nvfree(uninstaller);
nvfree(uninstall_log_path);
if (ret == 0) {
return TRUE;
}
}
return uninstall_existing_driver(op, FALSE /* interactive */,

View File

@@ -209,16 +209,18 @@ CommandList *build_command_list(Options *op, Package *p)
/* find any possibly conflicting modules and/or libraries */
if (!op->no_kernel_modules || op->dkms) {
if (!op->no_kernel_modules) {
find_conflicting_kernel_modules(op, l);
}
/* check the conflicting file list for any installed kernel modules */
if (op->kernel_modules_only) {
if (dkms_module_installed(op, p->version)) {
const char *kernel = get_kernel_name(op);
if (dkms_module_installed(op, p->version, kernel)) {
ui_error(op, "DKMS kernel modules with version %s are already "
"installed.", p->version);
"installed for the %s kernel.", p->version, kernel);
free_file_list(l);
free_command_list(op,c);
return NULL;
@@ -489,7 +491,7 @@ static inline int execute_run_command(Options *op, float percent, const char *cm
ui_expert(op, "Executing: %s", cmd);
ui_status_update(op, percent, "Executing: `%s` "
"(this may take a moment...)", cmd);
ret = run_command(op, cmd, &data, TRUE, 0, TRUE);
ret = run_command(op, cmd, &data, TRUE, NULL, TRUE);
if (ret != 0) {
ui_error(op, "Failed to execute `%s`: %s", cmd, data);
ret = continue_after_error(op, "Failed to execute `%s`", cmd);

View File

@@ -595,6 +595,89 @@ int nv_mkdir_recursive(const char *path, const mode_t mode,
}
/*
* nvdircat() - concatenate path elements, inserting a '/' path separator
* character between each element.
*/
char *nvdircat(const char *str, ...)
{
const char *s;
char *result = nvstrdup("");
va_list ap;
va_start(ap, str);
for (s = str; s; s = va_arg(ap, char *)) {
char *oldresult = result;
result = nvstrcat(result, s == str ? "" : "/", s, NULL);
nvfree(oldresult);
}
va_end(ap);
collapse_multiple_slashes(result);
return result;
}
/*
* dirname(3) workalike that abstracts away implementation-specific behavior:
* this function always returns a heap-allocated string that can be passed to
* free(3), and never modifies the contents of the original string.
*/
char *nv_dirname(const char *path)
{
char *last_slash = strrchr(path, '/');
if (last_slash) {
return nvstrndup(path, last_slash - path);
} else {
return nvstrdup(".");
}
}
/*
* Simple helper function to write the contents of a NUL-terminated string to
* a file. A trailing newline is appended if not already present.
* Returns TRUE on success; FALSE if an error occurred.
*/
int nv_string_to_file(const char *destination, const char *data)
{
char *dname = nv_dirname(destination);
int written, newline_success = TRUE;
char *error = NULL;
int len, ret;
FILE *fp;
ret = nv_mkdir_recursive(dname, 0755, &error, NULL);
nvfree(dname);
nvfree(error);
if (!ret) return FALSE;
fp = fopen(destination, "w");
if (!fp) return FALSE;
len = strlen(data);
written = fwrite(data, 1, len, fp);
if (data[len-1] != '\n') {
if (fwrite("\n", 1, 1, fp) != 1) {
newline_success = FALSE;
}
}
if (fclose(fp)) return FALSE;
if (chmod(destination, 0644)) return FALSE;
return written == len && newline_success;
}
/****************************************************************************/
/* string helper functions */
/****************************************************************************/
@@ -720,3 +803,24 @@ void remove_trailing_slashes(char *string)
}
/*
* collapse_multiple_slashes() - remove any/all occurrences of "//" from the
* argument string.
*/
void collapse_multiple_slashes(char *s)
{
char *p;
while ((p = strstr(s, "//")) != NULL) {
p++; /* advance to second '/' */
while (*p == '/') {
unsigned int i, len;
len = strlen(p);
for (i = 0; i < len; i++) p[i] = p[i+1];
}
}
}

View File

@@ -75,11 +75,15 @@ void *nv_mmap(const char *filename, size_t len, int prot, int flags, int fd);
char *nv_basename(const char *path);
int nv_mkdir_recursive(const char *path, const mode_t mode,
char **error_str, char **log_str);
char *nvdircat(const char *str, ...);
char *nv_dirname(const char *path);
int nv_string_to_file(const char *, const char *);
char *nv_trim_space(char *string);
char *nv_trim_char(char *string, char trim);
char *nv_trim_char_strict(char *string, char trim);
void remove_trailing_slashes(char *string);
void collapse_multiple_slashes(char *s);
int directory_exists(const char *dir);

View File

@@ -43,7 +43,7 @@
* through 'boolval'.
*/
#define NVGETOPT_IS_BOOLEAN 0x01
#define NVGETOPT_IS_BOOLEAN 0x0001
/*
@@ -52,7 +52,7 @@
* through 'strval'.
*/
#define NVGETOPT_STRING_ARGUMENT 0x02
#define NVGETOPT_STRING_ARGUMENT 0x0002
/*
@@ -61,7 +61,7 @@
* argument through 'intval'.
*/
#define NVGETOPT_INTEGER_ARGUMENT 0x04
#define NVGETOPT_INTEGER_ARGUMENT 0x0004
/*
@@ -70,7 +70,7 @@
* argument through 'doubleval'.
*/
#define NVGETOPT_DOUBLE_ARGUMENT 0x08
#define NVGETOPT_DOUBLE_ARGUMENT 0x0008
/* helper macro */
@@ -89,7 +89,7 @@
* take arguments.
*/
#define NVGETOPT_ALLOW_DISABLE 0x10
#define NVGETOPT_ALLOW_DISABLE 0x0010
/*
@@ -99,7 +99,7 @@
* option is returned without an argument.
*/
#define NVGETOPT_ARGUMENT_IS_OPTIONAL 0x20
#define NVGETOPT_ARGUMENT_IS_OPTIONAL 0x0020
/*
@@ -110,9 +110,28 @@
* printed.
*/
#define NVGETOPT_HELP_ALWAYS 0x40
#define NVGETOPT_HELP_ALWAYS 0x0040
/*
* Indicates that an option is deprecated. The description field of the
* NVGetoptOption, if set, may be used to store text explaining why the
* option is no longer used.
*/
#define NVGETOPT_IS_DEPRECATED 0x0080
/*
* These flags indicate that a particular boolean or disableable value is no
* longer supported. They can be used together with NVGETOPT_DEPRECATED in
* order to differentiate between deprecated boolean values or enable/disable
* states that will be ignored, and unsupported boolean values or enable/disable
* states that are invalid.
*/
#define NVGETOPT_DISABLE_IS_INVALID 0x0100
#define NVGETOPT_ENABLE_IS_INVALID 0x0200
typedef struct {
const char *name;
int val;

20
files.c
View File

@@ -311,7 +311,7 @@ int copy_file(Options *op, const char *srcfile,
*/
char *write_temp_file(Options *op, const int len,
const unsigned char *data, mode_t perm)
const void *data, mode_t perm)
{
unsigned char *dst = (void *) -1;
char *tmpfile = NULL;
@@ -1552,7 +1552,7 @@ char *make_tmpdir(Options *op)
remove_directory(op, tmpdir);
}
if (!mkdir_recursive(op, tmpdir, 0655, FALSE)) {
if (!mkdir_recursive(op, tmpdir, 0755, FALSE)) {
return NULL;
}
@@ -1626,7 +1626,7 @@ int check_for_existing_rpms(Options *op)
cmd = nvstrcat("env LD_KERNEL_ASSUME=2.2.5 rpm --query ",
rpms[i], NULL);
ret = run_command(op, cmd, NULL, FALSE, 0, TRUE);
ret = run_command(op, cmd, NULL, FALSE, NULL, TRUE);
nvfree(cmd);
if (ret == 0) {
@@ -1644,7 +1644,7 @@ int check_for_existing_rpms(Options *op)
}
cmd = nvstrcat("rpm --erase --nodeps ", rpms[i], NULL);
ret = run_command(op, cmd, &data, op->expert, 0, TRUE);
ret = run_command(op, cmd, &data, op->expert, NULL, TRUE);
nvfree(cmd);
if (ret == 0) {
@@ -2193,7 +2193,7 @@ int set_security_context(Options *op, const char *filename, const char *type)
cmd = nvstrcat(op->utils[CHCON], " -t ", type, " ", filename, NULL);
ret = run_command(op, cmd, NULL, FALSE, 0, TRUE);
ret = run_command(op, cmd, NULL, FALSE, NULL, TRUE);
ret = ((ret == 0) ? TRUE : FALSE);
nvfree(cmd);
@@ -2255,7 +2255,7 @@ static char *get_ldconfig_cache(Options *op)
int ret;
cmd = nvstrcat(op->utils[LDCONFIG], " -p", NULL);
ret = run_command(op, cmd, &data, FALSE, 0, FALSE);
ret = run_command(op, cmd, &data, FALSE, NULL, FALSE);
nvfree(cmd);
if (ret != 0) {
@@ -2673,7 +2673,7 @@ static int get_x_paths_helper(Options *op,
dirs = NULL;
cmd = nvstrcat(op->utils[XSERVER], " ", xserver_cmd, NULL);
ret = run_command(op, cmd, &dirs, FALSE, 0, TRUE);
ret = run_command(op, cmd, &dirs, FALSE, NULL, TRUE);
nvfree(cmd);
if ((ret == 0) && dirs) {
@@ -2720,7 +2720,7 @@ static int get_x_paths_helper(Options *op,
dirs = NULL;
cmd = nvstrcat(op->utils[PKG_CONFIG], " ",
pkg_config_cmd, NULL);
ret = run_command(op, cmd, &dirs, FALSE, 0, TRUE);
ret = run_command(op, cmd, &dirs, FALSE, NULL, TRUE);
nvfree(cmd);
if ((ret == 0) && dirs) {
@@ -2907,7 +2907,7 @@ int secure_delete(Options *op, const char *file)
int ret;
char *cmdline = nvstrcat(cmd, " -u \"", file, "\"", NULL);
ret = run_command(op, cmdline, NULL, FALSE, 0, TRUE);
ret = run_command(op, cmdline, NULL, FALSE, NULL, TRUE);
log_printf(op, NULL, "%s: %s", cmdline, ret == 0 ? "" : "failed!");
nvfree(cmd);
@@ -3121,7 +3121,7 @@ static LibglvndInstallCheckResult run_libglvnd_script(Options *op, Package *p,
}
cmdline = nvasprintf("/bin/sh %s", scriptPath);
status = run_command(op, cmdline, &output, TRUE, 0, FALSE);
status = run_command(op, cmdline, &output, TRUE, NULL, FALSE);
if (WIFEXITED(status)) {
result = WEXITSTATUS(status);
} else {

View File

@@ -28,7 +28,7 @@ int touch_directory(Options *op, const char *victim);
int copy_file(Options *op, const char *srcfile,
const char *dstfile, mode_t mode);
char *write_temp_file(Options *op, const int len,
const unsigned char *data, mode_t perm);
const void *data, mode_t perm);
int set_destinations(Options *op, Package *p); /* XXX move? */
int get_prefixes(Options *op); /* XXX move? */
void add_kernel_modules_to_package(Options *op, Package *p);

View File

@@ -213,15 +213,6 @@ int install_from_cwd(Options *op)
"an earlier NVIDIA driver installation. Please ensure "
"that NVIDIA kernel modules matching this driver version "
"are installed separately.");
/* no_kernel_modules should imply no DKMS */
if (op->dkms) {
ui_warn(op, "You have specified both the '--no-kernel-module' "
"and the '--dkms' command line options. The '--dkms' "
"option will be ignored.");
op->dkms = FALSE;
}
}
/*
@@ -259,6 +250,8 @@ int install_from_cwd(Options *op)
if (op->no_opengl_files) {
remove_opengl_files_from_package(p);
} else {
check_for_vulkan_loader(op);
}
if (op->no_wine_files) {
@@ -331,17 +324,12 @@ int install_from_cwd(Options *op)
if (!do_install(op, p, c)) goto failed;
/* Register, build, and install the module with DKMS, if requested */
if (op->dkms && !dkms_install_module(op, p->version, get_kernel_name(op)))
goto failed;
/*
* Leave nvidia-drm loaded in case an X server with OutputClass-based driver
* matching is being used.
*/
if (!op->no_kernel_modules || op->dkms) {
if (!op->no_kernel_modules) {
if (package_includes_kernel_module(p, "nvidia-drm")) {
if (!load_kernel_module(op, "nvidia-drm")) {
goto failed;
@@ -366,6 +354,14 @@ int install_from_cwd(Options *op)
check_installed_files_from_package(op, p);
/*
* Import the kernel modules into DKMS, if requested. This is done after
* the post-install sanity check because DKMS may move or rename files
*/
dkms_register_module(op, p, get_kernel_name(op));
/* done */
if (!op->kernel_modules_only) {
@@ -462,26 +458,6 @@ static int install_kernel_modules(Options *op, Package *p)
process_dkms_conf(op,p);
/* Offer the DKMS option if DKMS exists and the kernel module sources
* will be installed somewhere. Don't offer DKMS as an option if module
* signing was requested. */
if (op->utils[DKMS] && !op->no_kernel_module_source &&
!(op->module_signing_secret_key && op->module_signing_public_key)) {
op->dkms = ui_yes_no(op, op->dkms,
"Would you like to register the kernel module "
"sources with DKMS? This will allow DKMS to "
"automatically build a new module, if you "
"install a different kernel later.");
}
/* Only do the normal kernel module install if not using DKMS */
if (op->dkms) {
op->no_kernel_modules = TRUE;
return TRUE;
}
/* determine where to install the kernel module */
if (!determine_kernel_module_installation_path(op)) return FALSE;
@@ -908,6 +884,9 @@ static Package *parse_manifest (Options *op)
case FILE_TYPE_XMODULE_SHARED_LIB:
op->x_files_packaged = TRUE;
break;
case FILE_TYPE_VULKAN_ICD_JSON:
op->vulkan_icd_json_packaged = TRUE;
break;
default: break;
}
@@ -1132,6 +1111,8 @@ static void free_package(Package *p)
nvfree(p->excluded_kernel_modules);
nvfree(p->kernel_make_logs);
for (i = 0; i < p->num_entries; i++) {
nvfree(p->entries[i].file);
nvfree(p->entries[i].path);
@@ -1249,6 +1230,10 @@ static int assisted_module_signing(Options *op, Package *p)
if (generate_keys) {
char *cmdline, *x509_hash, *private_key_path, *public_key_path;
int ret, generate_failed = FALSE;
const RunCommandOutputMatch output_match[] = {
{ .lines = 8, .initial_match = NULL },
{ 0 }
};
if (!op->utils[OPENSSL]) {
ui_error(op, "Unable to generate key pair: openssl not "
@@ -1340,7 +1325,7 @@ guess_fail:
" -", x509_hash, NULL);
nvfree(x509_hash);
ret = run_command(op, cmdline, NULL, TRUE, 8, TRUE);
ret = run_command(op, cmdline, NULL, TRUE, output_match, TRUE);
nvfree(cmdline);
@@ -1405,7 +1390,7 @@ generate_done:
cmdline = nvstrcat(op->utils[OPENSSL], " x509 -noout -fingerprint ",
"-inform DER -in ", op->module_signing_public_key,
NULL);
ret = run_command(op, cmdline, &result, FALSE, 0, FALSE);
ret = run_command(op, cmdline, &result, FALSE, NULL, FALSE);
nvfree(cmdline);
/* Format: "SHA1 Fingerprint=00:00:00:00:..." */
@@ -1419,7 +1404,7 @@ generate_done:
* incorrectly; try to get a sha1sum of the DER certificate */
cmdline = nvstrcat(sha1sum, " ", op->module_signing_public_key,
NULL);
ret = run_command(op, cmdline, &result, FALSE, 0, FALSE);
ret = run_command(op, cmdline, &result, FALSE, NULL, FALSE);
nvfree(sha1sum);
nvfree(cmdline);

273
kernel.c
View File

@@ -57,11 +57,11 @@ static PrecompiledInfo *scan_dir(Options *op, Package *p,
static char *build_distro_precompiled_kernel_interface_dir(Options *op);
static char *convert_include_path_to_source_path(const char *inc);
static char *get_machine_arch(Options *op);
static int run_conftest(Options *op, const char *dir, const char *args,
char **result);
static int run_make(Options *op, Package *p, const char *dir, const char *target,
char **vars, const char *status, int lines);
static int run_make(Options *op, Package *p, const char *dir,
const char *cli_options, const char *status,
const RunCommandOutputMatch *match);
static void load_kernel_module_quiet(Options *op, const char *module_name);
static void modprobe_remove_kernel_module_quiet(Options *op, const char *name);
static int kernel_configuration_conflict(Options *op, Package *p,
@@ -155,7 +155,8 @@ int determine_kernel_module_installation_path(Options *op)
static int run_conftest(Options *op, const char *dir, const char *args,
char **result)
{
char *cmd, *arch, *kernel_source_path, *kernel_output_path;
char *cmd, *kernel_source_path, *kernel_output_path;
const char *arch;
int ret;
if (result) {
@@ -544,6 +545,84 @@ int unpack_kernel_modules(Options *op, Package *p, const char *build_directory,
}
/*
* Estimate the number of expected lines of output that will be produced by
* building the kernel modules. single_module may be set to restrict the
* estimate to the result of building the specified module only.
*/
static RunCommandOutputMatch *count_lines(Options *op, Package *p,
const char *dir,
const char *single_module)
{
RunCommandOutputMatch *ret = nvalloc(sizeof(*ret) * 5);
int conftest_count, object_count, module_count, count_success = FALSE;
char *data = NULL, *cmd;
/*
* Build the make(1) command line. run_make() is explicitly avoided here:
* the output from count-lines.mk shouldn't be logged or displayed.
*/
cmd = nvstrcat("cd ", dir, "; ",
op->utils[MAKE], " -f count-lines.mk count "
"NV_EXCLUDE_KERNEL_MODULES=", p->excluded_kernel_modules,
single_module ? "" : NULL,
" NV_KERNEL_MODULES=", single_module,
NULL);
if (run_command(op, cmd, &data, FALSE, NULL, TRUE) == 0) {
if (sscanf(data, "conftests:%d objects:%d modules:%d",
&conftest_count, &object_count, &module_count) == 3) {
count_success = TRUE;
}
}
if (!count_success) {
/*
* Something went wrong, but since the counts are only used for cosmetic
* purposes, it is sufficient to log the error and silently fall back to
* approximate default values.
*/
ui_log(op, "Failed to estimate output lines: %s", data);
conftest_count = 250; object_count = 200; module_count = 5;
}
/*
* One line each for entering and leaving each of the Kbuild source and
* output directories
*/
ret[0].lines = 4;
ret[0].initial_match = "make[";
/*
* Each C source file that is compiled into an object file generates one
* line of output beginning with " CC [M] ". Additionally, for each module
* a $module_name.mod.o file is compiled, outputting a line that begins with
* " CC " on older kernels and " CC [M] " on newer ones.
*/
ret[1].lines = object_count + module_count;
ret[1].initial_match = " CC ";
/*
* Each module has has a $module_name.o object linked before the MODPOST
* stage, and a $module_name.ko object linked after. For both linking steps,
* a line beginning with " LD [M] " is printed.
*/
ret[2].lines = module_count * 2;
ret[2].initial_match = " LD [M] ";
/*
* Expect one line of output per conftest, and assume that all the conftests
* have already been run in the "rebuild a single module to isolate modules
* that failed to build" case.
*/
if (single_module == NULL) {
ret[3].lines = conftest_count;
ret[3].initial_match = " CONFTEST: ";
}
return ret;
}
static int check_file(Options *op, Package *p, const char *dir,
const char *modname)
@@ -560,11 +639,13 @@ static int check_file(Options *op, Package *p, const char *dir,
char *rebuild_msg = nvstrcat("Checking to see whether the ", modname,
" kernel module was successfully built",
NULL);
RunCommandOutputMatch *match = count_lines(op, p, dir, modname);
/* Attempt to rebuild the individual module, in case the failure
* is module-specific and due to a different module */
run_make(op, p, dir, single_module_list, NULL, rebuild_msg, 25);
run_make(op, p, dir, single_module_list, rebuild_msg, match);
nvfree(single_module_list);
nvfree(rebuild_msg);
nvfree(match);
/* Check the file again */
ret = access(path, F_OK);
@@ -591,33 +672,6 @@ int build_kernel_modules(Options *op, Package *p)
}
/*
* Run the module_signing_script with three or four arguments.
* Return TRUE on success.
*/
static int try_sign_file(Options *op, const char *file, int num_args)
{
char *cmd;
const char *arg_1;
int ret;
switch (num_args) {
case 3: arg_1 = ""; break;
case 4: arg_1 = op->module_signing_hash; break;
default: return FALSE;
}
cmd = nvstrcat("\"", op->module_signing_script, "\" ",
arg_1, " \"",
op->module_signing_secret_key, "\" \"",
op->module_signing_public_key, "\" \"",
file, "\"", NULL);
ret = run_command(op, cmd, NULL, TRUE, 1, TRUE);
nvfree(cmd);
return ret == 0;
}
/*
* Check to see if scripts/sign-file exists under 'dir' and is executable
@@ -645,9 +699,12 @@ static char *test_sign_file(const char *dir)
*/
int sign_kernel_module(Options *op, const char *build_directory,
const char *module_filename, int status) {
char *file;
const RunCommandOutputMatch output_match[] = {
{ .lines = 1, .initial_match = NULL },
{ 0 }
};
int success;
static int num_args = 3;
char *cmd;
/* Lazily set the default value for module_signing_script. */
@@ -671,39 +728,27 @@ int sign_kernel_module(Options *op, const char *build_directory,
ui_status_begin(op, "Signing kernel module:", "Signing");
}
file = nvstrcat(build_directory, "/", module_filename, NULL);
try_sign:
success = try_sign_file(op, file, num_args);
/* If sign-file failed to run with three arguments, try running it with
* four arguments on all subsequent signing attempts. */
if (num_args == 3 && !success) {
num_args = 4;
/* The four-arg version of sign-file needs a hash. */
if (!op->module_signing_hash) {
op->module_signing_hash = guess_module_signing_hash(op,
build_directory);
}
if (op->module_signing_hash) {
goto try_sign;
} else {
ui_error(op, "The installer was unable to sign %s without "
"specifying a hash algorithm on the command line to %s, "
"and was also unable to automatically detect the hash. "
"If you need to sign the NVIDIA kernel modules, please "
"try again and set the '--module-signing-hash' option on "
"the installer's command line.",
file, op->module_signing_script);
}
if (!op->module_signing_hash) {
op->module_signing_hash = guess_module_signing_hash(op,
build_directory);
}
nvfree(file);
if (!op->module_signing_hash) {
ui_error(op, "The installer cannot sign %s without specifying a hash "
"algorithm on the command line to %s, and was also unable to "
"automatically detect the hash. If you need to sign the "
"NVIDIA kernel modules, please try again and set the "
"'--module-signing-hash' option on the installer's command "
"line.", module_filename, op->module_signing_script);
}
cmd = nvstrcat("\"", op->module_signing_script, "\" ",
op->module_signing_hash, " \"",
op->module_signing_secret_key, "\" \"",
op->module_signing_public_key, "\" \"",
build_directory, "/", module_filename, "\"", NULL);
success = (run_command(op, cmd, NULL, TRUE, output_match, TRUE) == 0);
nvfree(cmd);
if (status) {
ui_status_end(op, success ? "done." : "Failed to sign kernel module.");
@@ -894,6 +939,7 @@ int build_kernel_interfaces(Options *op, Package *p,
{
char *tmpdir = NULL, *builddir;
int ret, files_packaged = 0, i;
RunCommandOutputMatch *match;
struct {
const char *sanity_check_name;
@@ -957,8 +1003,11 @@ int build_kernel_interfaces(Options *op, Package *p,
}
ui_log(op, "Cleaning kernel module build directory.");
run_make(op, p, builddir, "clean", NULL, NULL, 0);
ret = run_make(op, p, builddir, "", NULL, "Building kernel modules", 25);
run_make(op, p, builddir, "clean", NULL, 0);
match = count_lines(op, p, builddir, NULL);
ret = run_make(op, p, builddir, "", "Building kernel modules", match);
nvfree(match);
/* Test to make sure that all kernel modules were built. */
for (i = 0; i < p->num_kernel_modules; i++) {
@@ -999,7 +1048,7 @@ int build_kernel_interfaces(Options *op, Package *p,
if (module->has_separate_interface_file) {
if (!(run_make(op, p, tmpdir, module->interface_filename,
NULL, NULL, 0) &&
NULL, NULL) &&
pack_kernel_interface(op, p, tmpdir, fileInfo,
module->interface_filename,
module->module_filename,
@@ -1226,7 +1275,7 @@ static int ignore_load_error(Options *op, Package *p,
probable_reason,
signature_related) == 0);
} else {
const char *secureboot_message, *dkms_message;
const char *secureboot_message;
secureboot_message = secureboot == 1 ?
"and sign the kernel module when "
@@ -1238,14 +1287,10 @@ static int ignore_load_error(Options *op, Package *p,
"enable the interactive module "
"signing prompts.";
dkms_message = op->dkms ? " Module signing is incompatible "
"with DKMS, so please select the "
"non-DKMS option when building the "
"kernel module to be signed." : "";
ui_error(op, "The kernel module failed to load%s because it "
"was not signed by a key that is trusted by the "
"kernel. Please try installing the driver again, %s%s",
probable_reason, secureboot_message, dkms_message);
"kernel. Please try installing the driver again, %s",
probable_reason, secureboot_message);
}
}
@@ -1321,7 +1366,7 @@ static void toggle_udev_event_queue(Options *op, int enable)
NULL);
nvfree(udevadm);
cmd_ret = run_command(op, cmd, &data, FALSE, 0, TRUE) != 0;
cmd_ret = run_command(op, cmd, &data, FALSE, NULL, TRUE) != 0;
nvfree(cmd);
if (cmd_ret != 0) {
@@ -1452,7 +1497,7 @@ static int test_kernel_modules_helper(Options *op, Package *p, int pause_udev)
cmd = nvstrcat(op->utils[DMESG], " | ",
op->utils[TAIL], " -n 25", NULL);
if (!run_command(op, cmd, &data, FALSE, 0, TRUE))
if (!run_command(op, cmd, &data, FALSE, NULL, TRUE))
ui_log(op, "Kernel messages:\n%s", data);
nvfree(cmd);
@@ -1526,7 +1571,7 @@ static int modprobe_helper(Options *op, const char *module_name,
loglevel_set = set_loglevel(PRINTK_LOGLEVEL_KERN_ALERT, &old_loglevel);
ret = run_command(op, cmd, &data, FALSE, 0, TRUE);
ret = run_command(op, cmd, &data, FALSE, NULL, TRUE);
if (loglevel_set) {
set_loglevel(old_loglevel, NULL);
@@ -2084,7 +2129,7 @@ static int check_for_loaded_kernel_module(Options *op, const char *module_name)
char *result = NULL;
int ret, found = FALSE;
ret = run_command(op, op->utils[LSMOD], &result, FALSE, 0, TRUE);
ret = run_command(op, op->utils[LSMOD], &result, FALSE, NULL, TRUE);
if ((ret == 0) && (result) && (result[0] != '\0')) {
char *ptr;
@@ -2120,7 +2165,7 @@ int rmmod_kernel_module(Options *op, const char *module_name)
loglevel_set = set_loglevel(PRINTK_LOGLEVEL_KERN_ALERT, &old_loglevel);
ret = run_command(op, cmd, NULL, FALSE, 0, TRUE);
ret = run_command(op, cmd, NULL, FALSE, NULL, TRUE);
if (loglevel_set) {
set_loglevel(old_loglevel, NULL);
@@ -2279,74 +2324,59 @@ static char *convert_include_path_to_source_path(const char *inc)
/*
* get_machine_arch() - get the machine architecture, substituting
* i386 for i586 and i686 or arm for arm7l.
* get_machine_arch() - get the machine architecture
*/
static char __machine_arch[65];
char *get_machine_arch(Options *op)
const char *get_machine_arch(Options *op)
{
static char __machine_arch[65];
struct utsname uname_buf;
if (__machine_arch[0]) {
return __machine_arch;
}
if (uname(&uname_buf) == -1) {
ui_warn(op, "Unable to determine machine architecture (%s).",
strerror(errno));
return NULL;
} else {
if ((strncmp(uname_buf.machine, "i586", 4) == 0) ||
(strncmp(uname_buf.machine, "i686", 4) == 0)) {
strcpy(__machine_arch, "i386");
} else if ((strncmp(uname_buf.machine, "armv", 4) == 0)) {
strcpy(__machine_arch, "arm");
} else {
strncpy(__machine_arch, uname_buf.machine,
sizeof(__machine_arch));
}
strncpy(__machine_arch, uname_buf.machine, sizeof(__machine_arch) - 1);
return __machine_arch;
}
} /* get_machine_arch() */
/*
* Run `make` with the specified target and make variables. The variables
* are given in the form of a NULL-terminated array of alternating key
* and value strings, e.g. { "KEY1", "value1", "KEY2", "value2", NULL }.
* Run `make` with the options we need for the kernel module build, plus
* any user-supplied command line options.
*
* If a 'status' string is given, then a ui_status progress bar is shown
* using 'status' as the initial message, expecting 'lines' lines of output
* from the make command.
*/
static int run_make(Options *op, Package *p, const char *dir, const char *target,
char **vars, const char *status, int lines) {
static int run_make(Options *op, Package *p, const char *dir,
const char *cli_options, const char *status,
const RunCommandOutputMatch *match) {
char *cmd, *concurrency, *data = NULL;
int i = 0, ret;
int ret;
concurrency = nvasprintf(" -j%d ", op->concurrency_level);
cmd = nvstrcat("cd ", dir, "; ",
op->utils[MAKE], " -k", concurrency, target,
op->utils[MAKE], " -k", concurrency,
" NV_EXCLUDE_KERNEL_MODULES=\"",
p->excluded_kernel_modules, "\"",
" SYSSRC=\"", op->kernel_source_path, "\"",
" SYSOUT=\"", op->kernel_output_path, "\"",
" SYSOUT=\"", op->kernel_output_path, "\" ",
cli_options,
NULL);
nvfree(concurrency);
if (vars) {
while (vars[i] && vars[i+1]) {
char *old_cmd = cmd;
cmd = nvstrcat(old_cmd, " ", vars[i], "=\"", vars[i+1], "\"", NULL);
nvfree(old_cmd);
i += 2;
}
}
if (status) {
ui_status_begin(op, status, "");
}
ret = (run_command(op, cmd, &data, TRUE, status ? lines : 0, TRUE) == 0);
ret = (run_command(op, cmd, &data, TRUE, status ? match : NULL, TRUE) == 0);
if (status) {
if (ret) {
@@ -2366,15 +2396,24 @@ static int run_make(Options *op, Package *p, const char *dir, const char *target
status_extra = nvstrdup("");
}
ui_error(op, "An error occurred%s. See " DEFAULT_LOG_FILE_NAME
" for details.", status_extra);
ui_error(op, "An error occurred%s. See %s for details.",
status_extra, op->log_file_name);
ui_log(op, "The command `%s` failed with the following output:\n\n%s",
cmd, data);
nvfree(status_extra);
}
/* Append the make output to the running make log */
if (p->kernel_make_logs) {
char *old_logs = p->kernel_make_logs;
p->kernel_make_logs = nvstrcat(old_logs, data, NULL);
nvfree(old_logs);
nvfree(data);
} else {
p->kernel_make_logs = data;
}
nvfree(cmd);
nvfree(data);
return ret;
}

View File

@@ -43,6 +43,7 @@ int load_kernel_module (Options*, const char*);
int check_for_unloaded_kernel_module (Options*);
PrecompiledInfo *find_precompiled_kernel_interface (Options*, Package*);
char *get_kernel_name (Options*);
const char *get_machine_arch (Options*);
KernelConfigOptionStatus test_kernel_config_option (Options*, Package*,
const char*);
int sign_kernel_module (Options*, const char*,

18
log.c
View File

@@ -25,6 +25,8 @@
#include <errno.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include "nvidia-installer.h"
#include "misc.h"
@@ -67,7 +69,21 @@ void log_init(Options *op, int argc, char * const argv[])
int i;
if (!op->logging) return;
if (op->add_this_kernel && geteuid() != 0) {
/*
* Logging won't work at the default location when the user is not root,
* which is allowed for --add-this-kernel. Log to an alternative path
* which is more likely to work if the user hasn't already set one.
*/
if (strcmp(DEFAULT_LOG_FILE_NAME, op->log_file_name) == 0) {
char *basename = nv_basename(DEFAULT_LOG_FILE_NAME);
op->log_file_name = nvdircat(op->tmpdir, basename, NULL);
nvfree(basename);
}
}
log_file_stream = fopen(op->log_file_name, "w");
if (!log_file_stream) {

472
misc.c
View File

@@ -232,10 +232,12 @@ char *get_next_line(char *buf, char **end, char *start, int length)
* ui; if this is TRUE, then everyline of output that is read is sent
* to the ui.
*
* If the status parameter is greater than 0, it is interpreted as a
* rough estimate of how many lines of output will be generated by the
* command. This is used to compute the value that should be passed
* to ui_status_update() for every line of output that is received.
* If the output_match parameter is set to a { 0 }-terminated array of
* RunCommandOutputMatch records, it is interpreted as a rough estimate of how
* many lines of output (optionally requiring an initial substring match) will
* be generated by the command. This is used to compute the value that should
* be passed to ui_status_update() as lines of output are received. This may be
* set to NULL to skip the ui_status_update() updates.
*
* The redirect argument tells run_command() to redirect stderr to
* stdout so that all output is collected, or just stdout.
@@ -245,13 +247,14 @@ char *get_next_line(char *buf, char **end, char *start, int length)
*/
int run_command(Options *op, const char *cmd, char **data, int output,
int status, int redirect)
const RunCommandOutputMatch *output_match, int redirect)
{
int n, len, buflen, ret;
int n, len, buflen, ret, total_lines;
char *cmd2, *buf, *tmpbuf;
FILE *stream = NULL;
struct sigaction act, old_act;
float percent;
int *match_sizes = NULL;
if (data) *data = NULL;
@@ -319,6 +322,35 @@ int run_command(Options *op, const char *cmd, char **data, int output,
buf = NULL;
n = 0; /* output line counter */
if (output_match) {
int match_count, i;
/* Determine the total number of lines to match */
for (total_lines = i = 0; output_match[i].lines; i++) {
total_lines += output_match[i].lines;
}
match_count = i;
/* Cache the lengths of the .initial_match strings */
match_sizes = nvalloc(match_count * sizeof(*match_sizes));
for (i = 0; i < match_count; i++) {
if (output_match[i].initial_match) {
match_sizes[i] = strlen(output_match[i].initial_match);
}
}
/* Don't divide by zero */
if (total_lines == 0) total_lines = 1;
/*
* Note: 'match_sizes' and 'total_lines' must only be used when
* output_match != NULL; otherwise, 'match_sizes' cannot be safely
* dereferenced, and 'total_lines' is uninitialized.
*/
}
while (1) {
if ((buflen - len) < NV_MIN_LINE_LEN) {
@@ -334,13 +366,20 @@ int run_command(Options *op, const char *cmd, char **data, int output,
if (fgets(buf + len, buflen - len, stream) == NULL) break;
if (output) ui_command_output(op, "%s", buf + len);
len += strlen(buf + len);
if (status) {
n++;
if (n > status) n = status;
percent = (float) n / (float) status;
if (output_match) {
int i;
for (i = 0; output_match[i].lines; i++) {
const char *s = output_match[i].initial_match;
if (s == NULL || strncmp(buf + len, s, match_sizes[i]) == 0) {
n++;
break;
}
}
if (n > total_lines) n = total_lines;
percent = (float) n / (float) total_lines;
/*
* XXX: manually call the SIGWINCH handler, if set, to
@@ -351,8 +390,12 @@ int run_command(Options *op, const char *cmd, char **data, int output,
ui_status_update(op, percent, NULL);
}
len += strlen(buf + len);
} /* while (1) */
nvfree(match_sizes);
/* Close the popen()'ed stream. */
ret = pclose(stream);
@@ -466,6 +509,7 @@ static const Util __utils[] = {
[OPENSSL] = { "openssl", "openssl" },
[DKMS] = { "dkms", "dkms" },
[SYSTEMCTL] = { "systemctl", "systemd" },
[TAR] = { "tar", "tar" },
/* ModuleUtils */
[MODPROBE] = { "modprobe", "module-init-tools' or 'kmod" },
@@ -1280,7 +1324,7 @@ static int unprelink(Options *op, const char *filename)
if (cmd) {
char *cmdline;
cmdline = nvstrcat(cmd, " -u ", filename, NULL);
ret = run_command(op, cmdline, NULL, FALSE, 0, TRUE);
ret = run_command(op, cmdline, NULL, FALSE, NULL, TRUE);
nvfree(cmd);
nvfree(cmdline);
}
@@ -1393,27 +1437,6 @@ int check_installed_file(Options *op, const char *filename,
/*
* collapse_multiple_slashes() - remove any/all occurrences of "//" from the
* argument string.
*/
void collapse_multiple_slashes(char *s)
{
char *p;
unsigned int i, len;
while ((p = strstr(s, "//")) != NULL) {
p++; /* advance to second '/' */
while (*p == '/') {
len = strlen(p);
for (i = 0; i < len; i++) p[i] = p[i+1];
}
}
}
/*
* get_xserver_information() - parse the versionString (from `X
* -version`) and assign relevant information that we infer from the X
@@ -1512,7 +1535,7 @@ void query_xorg_version(Options *op)
cmd = nvstrcat(op->utils[XSERVER], " -version", NULL);
if (run_command(op, cmd, &data, FALSE, 0, TRUE) ||
if (run_command(op, cmd, &data, FALSE, NULL, TRUE) ||
(data == NULL)) {
goto done;
}
@@ -1749,7 +1772,7 @@ int check_selinux(Options *op)
if (selinux_available == TRUE) {
char *data = NULL;
int ret = run_command(op, op->utils[GETENFORCE], &data,
FALSE, 0, TRUE);
FALSE, NULL, TRUE);
if ((ret != 0) || (!data)) {
ui_warn(op, "Cannot check the current mode of SELinux; "
@@ -1770,7 +1793,7 @@ int check_selinux(Options *op)
op->selinux_enabled = FALSE;
if (selinux_available == TRUE) {
int ret = run_command(op, op->utils[SELINUX_ENABLED], NULL,
FALSE, 0, TRUE);
FALSE, NULL, TRUE);
if (ret == 0) {
op->selinux_enabled = TRUE;
}
@@ -1866,7 +1889,7 @@ int run_nvidia_xconfig(Options *op, int restore, const char *question,
cmd = nvstrcat(nvidia_xconfig, args, NULL);
cmd_ret = run_command(op, cmd, &data, FALSE, 0, TRUE);
cmd_ret = run_command(op, cmd, &data, FALSE, NULL, TRUE);
if (cmd_ret != 0) {
ui_error(op, "Failed to run `%s`:\n%s", cmd, data);
@@ -1928,7 +1951,7 @@ HookScriptStatus run_distro_hook(Options *op, const char *hook)
}
ui_status_begin(op, "Running distribution scripts", "Executing %s", cmd);
status = run_command(op, cmd, NULL, TRUE, 0, TRUE);
status = run_command(op, cmd, NULL, TRUE, NULL, TRUE);
ui_status_end(op, "done.");
ret = (status == 0) ? HOOK_SCRIPT_SUCCESS : HOOK_SCRIPT_FAIL;
@@ -2317,8 +2340,6 @@ int check_for_nouveau(Options *op)
}
#define DKMS_STATUS " status"
#define DKMS_ADD " add"
#define DKMS_BUILD " build"
#define DKMS_INSTALL " install"
#define DKMS_REMOVE " remove"
@@ -2328,10 +2349,6 @@ int check_for_nouveau(Options *op)
*
* DKMS_STATUS:
* Check the status of the specified module.
* DKMS_ADD: requires version
* Adds the module to the DKMS database.
* DKMS_BUILD: requires version
* Builds the module against the currently running kernel.
* DKMS_INSTALL: requires version
* Installs the module for the currently running kernel.
* DKMS_REMOVE: reqires version
@@ -2343,8 +2360,9 @@ int check_for_nouveau(Options *op)
static int run_dkms(Options *op, const char* verb, const char *version,
const char *kernel, char** out)
{
char *cmdline, *veropt, *kernopt = NULL, *kernopt_all = "";
char *cmdline, *veropt, *kernopt = NULL;
const char *modopt = " -m nvidia"; /* XXX real name is in the Package */
const char *kernopt_all = "", *depmod_opt = "";
char *output;
int ret;
@@ -2356,6 +2374,16 @@ static int run_dkms(Options *op, const char* verb, const char *version,
return FALSE;
}
/*
* Skip depmod when installing or removing, if the --no-depmod option is
* available. nvidia-installer already runs depmod(8) as part of the kernel
* module installation process.
*/
if ((strcmp(verb, DKMS_REMOVE) == 0 || strcmp(verb, DKMS_INSTALL) == 0) &&
option_is_supported(op, op->utils[DKMS], "--help", "--no-depmod")) {
depmod_opt = " --no-depmod";
}
/* Convert function parameters into commandline arguments. Optional
* arguments may be NULL, in which case nvstrcat() will end early. */
veropt = version ? nvstrcat(" -v ", version, NULL) : NULL;
@@ -2367,11 +2395,11 @@ static int run_dkms(Options *op, const char* verb, const char *version,
kernopt = kernel ? nvstrcat(" -k ", kernel, NULL) : NULL;
}
cmdline = nvstrcat(op->utils[DKMS], verb, modopt, veropt,
cmdline = nvstrcat(op->utils[DKMS], verb, depmod_opt, modopt, veropt,
kernopt_all, kernopt, NULL);
/* Run DKMS */
ret = run_command(op, cmdline, &output, FALSE, 0, TRUE);
ret = run_command(op, cmdline, &output, FALSE, NULL, TRUE);
if (ret != 0) {
ui_error(op, "Failed to run `%s`: %s", cmdline, output);
}
@@ -2390,48 +2418,239 @@ static int run_dkms(Options *op, const char* verb, const char *version,
/*
* Check to see whether the module is installed via DKMS.
* (The version parameter is optional: if NULL, check for any version; if
* non-NULL, check for the specified version only.)
* (The driver and kernel version parameters are optional: if NULL, check for
* any version; if non-NULL, check for the specified version only.)
*
* Returns TRUE if DKMS is found, and dkms commandline output is non-empty.
* Returns FALSE if DKMS not found, or dkms commandline output is empty.
* Returns TRUE if DKMS is found, and a matching installed driver is detected.
* Returns FALSE if DKMS not found, or no matching driver detected.
*/
int dkms_module_installed(Options* op, const char *version)
int dkms_module_installed(Options* op, const char *driver, const char *kernel)
{
int ret, bRet = FALSE;
int ret, matched = FALSE;
char *output = NULL;
ret = run_dkms(op, DKMS_STATUS, version, NULL, &output);
ret = run_dkms(op, DKMS_STATUS, driver, kernel, &output);
if (!ret || output == NULL) {
return FALSE;
}
if (driver != NULL && kernel != NULL) {
/*
* If a module and kernel version were specified, only match actually
* installed modules.
*/
if (strstr(output, ": installed") != NULL) {
matched = TRUE;
}
} else {
/*
* Otherwise, just match any non-empty output to detect modules in any
* state (added, built, installed).
*/
matched = output[0] != '\0';
}
if (output) bRet = strcmp("", output) != 0;
nvfree(output);
return ret && bRet;
return matched;
}
/*
* Install the given version of the module for the currently running kernel
* Generate a tar archive conforming to the `dkms mktarball --binaries-only`
* export format.
*/
int dkms_install_module(Options *op, const char *version, const char *kernel)
static char *dkms_gen_tarball(Options *op, Package *p, const char *kernel)
{
ui_status_begin(op, "Installing DKMS kernel module:", "Adding to DKMS");
if (!run_dkms(op, DKMS_ADD, version, kernel, NULL)) goto failed;
char *tmpdir, *binariesdir, *treedir, *builddir, *logdir, *moduledir, *dst;
char *tarball = NULL;
int ret, i;
ui_status_update(op, .05, "Building module (This may take a moment)");
if (!run_dkms(op, DKMS_BUILD, version, kernel, NULL)) goto failed;
tmpdir = make_tmpdir(op);
if (!tmpdir) return NULL;
ui_status_update(op, .9, "Installing module");
if( !run_dkms(op, DKMS_INSTALL, version, kernel, NULL)) goto failed;
binariesdir = nvdircat(tmpdir, "dkms_binaries_only", NULL);
treedir = nvdircat(tmpdir, "dkms_main_tree", NULL);
builddir = nvdircat(treedir, kernel, get_machine_arch(op), NULL);
logdir = nvdircat(builddir, "log", NULL);
moduledir = nvdircat(builddir, "module", NULL);
ui_status_end(op, "done.");
return TRUE;
/*
* DKMS 2.x checks for dkms_dbversion with a major version of 2.
* DKMS 3.x ignores dkms_dbversion. Write a dkms_dbversion file
* for compatibility with DKMS 2.x.
*/
dst = nvdircat(treedir, "dkms_dbversion", NULL);
ret = nv_string_to_file(dst, "2.0.0");
nvfree(dst);
if (!ret) goto done;
failed:
ui_status_end(op, "error.");
ui_error(op, "Failed to install the kernel module through DKMS. No kernel "
"module was installed; please try installing again without "
"DKMS, or check the DKMS logs for more information.");
return FALSE;
/* Write the build log to the tarball staging directory */
dst = nvdircat(logdir, "make.log", NULL);
ret = nv_string_to_file(dst, p->kernel_make_logs);
nvfree(dst);
if (!ret) goto done;
/* Write the "binaries_only" metadata to the tarball staging directory */
dst = nvdircat(binariesdir, "PACKAGE_NAME", NULL);
ret = nv_string_to_file(dst, "nvidia");
nvfree(dst);
if (!ret) goto done;
dst = nvdircat(binariesdir, "PACKAGE_VERSION", NULL);
ret = nv_string_to_file(dst, p->version);
nvfree(dst);
if (!ret) goto done;
/* Copy the (already installed) dkms.conf file to the staging directory */
ret = FALSE;
dst = nvdircat(binariesdir, "dkms.conf", NULL);
for (i = 0; i < p->num_entries; i++) {
if (p->entries[i].type == FILE_TYPE_DKMS_CONF) {
ret = copy_file(op, p->entries[i].dst, dst, 0644);
break;
}
}
nvfree(dst);
if (!ret) goto done;
ret = mkdir_recursive(op, moduledir, 0755, FALSE);
if (!ret) goto done;
/* Copy the (already built and installed) kernel modules */
for (i = 0; i < p->num_kernel_modules; i++) {
char *src = nvdircat(p->kernel_module_build_directory,
p->kernel_modules[i].module_filename, NULL);
dst = nvdircat(moduledir, p->kernel_modules[i].module_filename, NULL);
ret = copy_file(op, src, dst, 0644);
nvfree(src);
nvfree(dst);
if (!ret) goto done;
}
/* Reserve a name for a temporary file and run tar(1) to create a tarball */
tarball = write_temp_file(op, 0, NULL, 0644);
if (tarball) {
char *cmd = nvstrcat(op->utils[TAR], " -C ", tmpdir, " -cf ", tarball,
" .", NULL);
char *output;
ret = run_command(op, cmd, &output, FALSE, 0, TRUE);
nvfree(cmd);
if (ret != 0) {
ui_error(op, "Failed to create a DKMS tarball: %s", output);
}
nvfree(output);
if (ret != 0) {
unlink(tarball);
nvfree(tarball);
tarball = NULL;
goto done;
}
}
done:
remove_directory(op, tmpdir);
nvfree(tmpdir);
nvfree(binariesdir);
nvfree(treedir);
nvfree(builddir);
nvfree(logdir);
nvfree(moduledir);
return tarball;
}
/*
* Register the given version of the modules with DKMS. This is done by first
* generating and importing a tarball containing the (already built and
* installed) kernel modules and build log using `dkms ldtarball`, then creating
* a kernel-$kernel_version-$arch symbolic link in the DKMS tree to mark them
* as installed in the DKMS database.
*/
void dkms_register_module(Options *op, Package *p, const char *kernel)
{
char *tarball;
int ret = FALSE;
/* If dkms(8) or tar(1) are missing, there is nothing to do here. */
if (!op->utils[DKMS] || !op->utils[TAR]) return;
/*
* Offer the DKMS option if DKMS exists and the kernel modules and their
* sources were installed somewhere.
*/
if (op->no_kernel_modules || op->no_kernel_module_source) return;
op->dkms = ui_yes_no(op, op->dkms,
"Would you like to register the kernel module sources "
"with DKMS? This will allow DKMS to automatically "
"build a new module, if your kernel changes later.");
/* If the user decided not to use DKMS, there is nothing to do here. */
if (!op->dkms) return;
ui_status_begin(op, "Registering the kernel modules with DKMS:",
"Generating DKMS tarball");
/* Create a DKMS "binaries_only" tarball */
tarball = dkms_gen_tarball(op, p, kernel);
if (tarball) {
char *cmd, *output;
/* Load the tarball into the DKMS tree */
ui_status_update(op, .5, "Importing DKMS tarball");
cmd = nvstrcat(op->utils[DKMS], " ldtarball ", tarball, NULL);
ret = run_command(op, cmd, &output, FALSE, 0, TRUE);
nvfree(cmd);
if (ret != 0) {
ui_error(op, "Failed to load DKMS tarball: %s", output);
}
unlink(tarball);
nvfree(tarball);
nvfree(output);
if (ret != 0) {
goto done;
}
} else {
ui_error(op, "Failed to create a DKMS tarball");
goto done;
}
/*
* After loading the tarball, the modules should be in the "built" state.
* Run `dkms install` so that DKMS can recognize the (already installed)
* modules as installed, and do other actions such as updating weak-modules.
*/
ui_status_update(op, .75, "Marking modules as installed");
ret = run_dkms(op, DKMS_INSTALL, p->version, kernel, NULL);
if (!ret) goto done;
/*
* As a final sanity check, make sure that `dkms status` shows that the
* kernel modules were successfully "installed".
*/
ret = dkms_module_installed(op, p->version, kernel);
done:
if (ret) {
ui_status_end(op, "done.");
} else {
ui_status_end(op, "Error.");
ui_warn(op, "Failed to register the NVIDIA kernel modules with DKMS. "
"The NVIDIA kernel modules were installed, but will not be "
"automatically rebuilt if you change your kernel.");
}
}
/*
@@ -2621,7 +2840,7 @@ get_pkg_config_variable(Options *op,
cmd = nvstrcat(op->utils[PKG_CONFIG],
" --variable=", variable, " ", pkg,
NULL);
ret = run_command(op, cmd, &prefix, FALSE, 0, TRUE);
ret = run_command(op, cmd, &prefix, FALSE, NULL, TRUE);
nvfree(cmd);
if (ret != 0 ||
@@ -2694,3 +2913,108 @@ int check_systemd(Options *op)
return TRUE;
}
/*
* Run `$cmd $help` to print the help text for "cmd", and examine it for the
* presence of "option". Returns TRUE if "option" was found.
*/
int option_is_supported(Options *op, const char *cmd, const char *help,
const char *option)
{
int option_found = FALSE, option_len = strlen(option);
char *cmdline = nvstrcat(cmd, " ", help, NULL);
char *helptext, *match;
/* Ignore the return value: some programs lack a dedicated "help" option
* and will simply print a help message and return failure when an invalid
* command line option is specified. */
run_command(op, cmdline, &helptext, FALSE, 0, TRUE);
nvfree(cmdline);
for (match = helptext; match && *match; match = strstr(match + 1, option)) {
int before_clear;
/*
* Look for "option": we want to make sure it is surrounded on both
* sides by whitespace, brackets, etc., or the beginning or end of the
* help text, to ignore substring matches.
*/
if (match == helptext) {
if (strncmp(match, option, option_len)) continue;
before_clear = TRUE;
} else {
const char *before = match - 1;
if (isspace(*before)) {
before_clear = TRUE;
} else {
switch (*before) {
case '[': case '<': case '|': case '-':
before_clear = TRUE; break;
default:;
}
}
}
if (before_clear) {
const char *after = match + option_len;
int after_clear;
if (isspace(*after)) {
after_clear = TRUE;
} else {
switch (*after) {
case '\0': case ']': case '>': case '|':
after_clear = TRUE; break;
default:;
}
}
if (after_clear) {
option_found = TRUE;
break;
}
}
}
nvfree(helptext);
return option_found;
}
/* Attempt to dlopen(3) a DSO to detect its availability. */
static int detect_library(const char *library)
{
void *handle = dlopen(library, RTLD_NOW);
if (handle) {
dlclose(handle);
return TRUE;
}
return FALSE;
}
/* Test if the system has a Vulkan loader; warn if none is detected */
void check_for_vulkan_loader(Options *op)
{
if (!op->vulkan_icd_json_packaged) {
/*
* Don't check for a Vulkan loader if the package does not include
* the Vulkan ICD.
*/
return;
}
if (!detect_library("libvulkan.so.1")) {
ui_warn(op, "This NVIDIA driver package includes Vulkan components, "
"but no Vulkan ICD loader was detected on this system. "
"The NVIDIA Vulkan ICD will not function without the loader. "
"Most distributions package the Vulkan loader; try installing "
"the \"vulkan-loader\", \"vulkan-icd-loader\", or "
"\"libvulkan1\" package.");
}
}

24
misc.h
View File

@@ -50,13 +50,27 @@ typedef enum {
ELF_ARCHITECTURE_64,
} ElfFileType;
/*
* An { 0 }-terminated array of RunCommandOutputMatch records may be passed
* to run_command to have it update a progress bar as the command prints output.
*/
typedef struct {
/* The number of expected matching output lines */
int lines;
/*
* If set to non-NULL, lines must begin with initial_match to match.
* If set to NULL, all lines will match.
*/
char *initial_match;
} RunCommandOutputMatch;
char *read_next_word (char *buf, char **e);
int check_euid(Options *op);
int adjust_cwd(Options *op, const char *program_name);
char *get_next_line(char *buf, char **e, char *start, int length);
int run_command(Options *op, const char *cmd, char **data,
int output, int status, int redirect);
int output, const RunCommandOutputMatch *match, int redirect);
int read_text_file(const char *filename, char **buf);
char *find_system_util(const char *util);
int find_system_utils(Options *op);
@@ -75,7 +89,6 @@ void should_install_optional_modules(Options *op, Package *p,
void check_installed_files_from_package(Options *op, Package *p);
int check_installed_file(Options*, const char*, const mode_t, const uint32,
ui_message_func *logwarn);
void collapse_multiple_slashes(char *s);
int check_for_running_x(Options *op);
void query_xorg_version(Options *op);
void check_for_nvidia_graphics_devices(Options *op, Package *p);
@@ -83,8 +96,8 @@ int run_nvidia_xconfig(Options *op, int restore, const char *question, int answe
HookScriptStatus 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);
int dkms_module_installed(Options *op, const char *module, const char *kernel);
void dkms_register_module(Options *op, Package *p, const char *kernel);
int dkms_remove_module(Options *op, const char *version);
int verify_crc(Options *op, const char *filename, unsigned int crc,
unsigned int *actual_crc);
@@ -94,5 +107,8 @@ void set_concurrency_level(Options *op);
char *get_pkg_config_variable(Options *op,
const char *pkg, const char *variable);
int check_systemd(Options *op);
int option_is_supported(Options *op, const char *cmd, const char *help,
const char *option);
void check_for_vulkan_loader(Options *op);
#endif /* __NVIDIA_INSTALLER_MISC_H__ */

View File

@@ -135,7 +135,7 @@ static Options *load_default_options(void)
op->sigwinch_workaround = TRUE;
op->run_distro_scripts = TRUE;
op->no_kernel_module_source = FALSE;
op->dkms = FALSE;
op->dkms = TRUE;
op->check_for_alternate_installs = TRUE;
op->install_uvm = TRUE;
op->install_drm = TRUE;
@@ -417,7 +417,7 @@ static void parse_commandline(int argc, char *argv[], Options *op)
op->no_kernel_module_source = TRUE;
break;
case DKMS_OPTION:
op->dkms = TRUE;
op->dkms = boolval;
break;
case MODULE_SIGNING_SECRET_KEY_OPTION:
op->module_signing_secret_key = strval;
@@ -541,17 +541,6 @@ static void parse_commandline(int argc, char *argv[], Options *op)
exit(0);
}
/* Disable DKMS if module signing was requested; the two options are
* mutually exclusive. */
if (op->dkms &&
op->module_signing_secret_key && op->module_signing_public_key) {
ui_warn(op, "You selected the DKMS kernel module option, and also "
"specified a pair of module signing keys. Keys cannot be "
"managed securely under the automated DKMS framework. The "
"DKMS option will be disabled.");
op->dkms = FALSE;
}
/*
* if the installer prefix was not specified, default it to the
@@ -629,7 +618,9 @@ int main(int argc, char *argv[])
/* check that we're running as root */
if (!check_euid(op)) goto done;
if (!op->add_this_kernel && !check_euid(op)) {
goto done;
}
/*
* find the system utilities we'll need

View File

@@ -55,6 +55,7 @@ typedef enum {
OPENSSL,
DKMS,
SYSTEMCTL,
TAR,
MAX_SYSTEM_OPTIONAL_UTILS
} SystemOptionalUtils;
@@ -217,6 +218,7 @@ typedef struct __options {
int install_peermem;
int compat32_files_packaged;
int x_files_packaged;
int vulkan_icd_json_packaged;
int concurrency_level;
int skip_module_load;
int skip_depmod;
@@ -423,6 +425,7 @@ typedef struct __package {
char *version;
char *kernel_module_build_directory;
char *precompiled_kernel_interface_directory;
char *kernel_make_logs;
PackageEntry *entries; /* array of filename/checksum/bytesize entries */
int num_entries;

View File

@@ -536,16 +536,15 @@ static const NVGetoptOption __options[] = {
{ "no-kernel-module-source", NO_KERNEL_MODULE_SOURCE_OPTION, 0, NULL,
"Skip installation of the kernel module source."},
{ "dkms", DKMS_OPTION, 0, NULL,
{ "dkms", DKMS_OPTION, NVGETOPT_IS_BOOLEAN, NULL,
"nvidia-installer can optionally register the NVIDIA kernel module "
"sources, if installed, with DKMS, then build and install a kernel "
"module using the DKMS-registered sources. This will allow the DKMS "
"infrastructure to automatically build a new kernel module when "
"changing kernels. During installation, if DKMS is detected, "
"nvidia-installer will ask the user if they wish to register the "
"module with DKMS; the default response is 'no'. This option will "
"bypass the detection of DKMS, and cause the installer to attempt a "
"DKMS-based installation regardless of whether DKMS is present."},
"module with DKMS; the default response is 'yes' unless the --no-dkms "
"option is set, in which case the default response is 'no'." },
{ "module-signing-secret-key", MODULE_SIGNING_SECRET_KEY_OPTION,
NVGETOPT_STRING_ARGUMENT, NULL,

View File

@@ -1,4 +1,4 @@
NVIDIA_VERSION = 515.76
NVIDIA_VERSION = 520.56.06
# This file.
VERSION_MK_FILE := $(lastword $(MAKEFILE_LIST))