mirror of
https://github.com/NVIDIA/nvidia-installer.git
synced 2025-07-23 02:13:00 +02:00
520.56.06
This commit is contained in:
44
backup.c
44
backup.c
@@ -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 */,
|
||||
|
@@ -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);
|
||||
|
@@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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
20
files.c
@@ -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 {
|
||||
|
2
files.h
2
files.h
@@ -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);
|
||||
|
@@ -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
273
kernel.c
@@ -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;
|
||||
}
|
||||
|
1
kernel.h
1
kernel.h
@@ -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
18
log.c
@@ -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
472
misc.c
@@ -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
24
misc.h
@@ -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__ */
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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,
|
||||
|
@@ -1,4 +1,4 @@
|
||||
NVIDIA_VERSION = 515.76
|
||||
NVIDIA_VERSION = 520.56.06
|
||||
|
||||
# This file.
|
||||
VERSION_MK_FILE := $(lastword $(MAKEFILE_LIST))
|
||||
|
Reference in New Issue
Block a user