mirror of
https://github.com/NVIDIA/nvidia-installer.git
synced 2025-07-23 02:13:00 +02:00
545.23.06
This commit is contained in:
8
Makefile
8
Makefile
@@ -131,7 +131,7 @@ CFLAGS += $(common_cflags)
|
||||
HOST_CFLAGS += $(common_cflags)
|
||||
|
||||
LDFLAGS += -L.
|
||||
LIBS += -ldl
|
||||
LIBS += -ldl -lpthread
|
||||
|
||||
MKPRECOMPILED_SRC = crc.c mkprecompiled.c $(COMMON_UTILS_DIR)/common-utils.c \
|
||||
precompiled.c $(COMMON_UTILS_DIR)/nvgetopt.c
|
||||
@@ -207,15 +207,15 @@ $(GEN_UI_ARRAY): gen-ui-array.c $(CONFIG_H)
|
||||
|
||||
$(NCURSES_UI_SO): $(NCURSES_UI_O)
|
||||
$(call quiet_cmd,LINK) -shared $(NCURSES_LDFLAGS) \
|
||||
$(CFLAGS) $(LDFLAGS) $(BIN_LDFLAGS) $< -o $@ -lncurses $(LIBS)
|
||||
$(CFLAGS) $(LDFLAGS) $(BIN_LDFLAGS) $^ -o $@ -lncurses $(LIBS)
|
||||
|
||||
$(NCURSES6_UI_SO): $(NCURSES6_UI_O)
|
||||
$(call quiet_cmd,LINK) -shared $(NCURSES6_LDFLAGS) \
|
||||
$(CFLAGS) $(LDFLAGS) $(BIN_LDFLAGS) $< -o $@ -lncurses $(LIBS)
|
||||
$(CFLAGS) $(LDFLAGS) $(BIN_LDFLAGS) $^ -o $@ -lncurses $(LIBS)
|
||||
|
||||
$(NCURSESW6_UI_SO): $(NCURSESW6_UI_O)
|
||||
$(call quiet_cmd,LINK) -shared $(NCURSESW6_LDFLAGS) \
|
||||
$(CFLAGS) $(LDFLAGS) $(BIN_LDFLAGS) $< -o $@ -lncursesw $(LIBS)
|
||||
$(CFLAGS) $(LDFLAGS) $(BIN_LDFLAGS) $^ -o $@ -lncursesw $(LIBS)
|
||||
|
||||
$(NCURSES_UI_SO_C): $(GEN_UI_ARRAY) $(NCURSES_UI_SO)
|
||||
$(call quiet_cmd,GEN_UI_ARRAY) $(NCURSES_UI_SO) ncurses_ui_array > $@
|
||||
|
42
backup.c
42
backup.c
@@ -843,12 +843,12 @@ static int do_uninstall(Options *op, const char *version,
|
||||
ui_log(op, "Running %sldconfig:", op->skip_depmod ? "" : "depmod and ");
|
||||
|
||||
if (!op->skip_depmod) {
|
||||
char *cmd = nvstrcat(op->utils[DEPMOD], " -a ", op->kernel_name, NULL);
|
||||
status |= run_command(op, cmd, NULL, FALSE, NULL, FALSE);
|
||||
nvfree(cmd);
|
||||
status |= run_command(op, NULL, FALSE, NULL, FALSE,
|
||||
op->utils[DEPMOD], " -a ", op->kernel_name, NULL);
|
||||
}
|
||||
|
||||
status |= run_command(op, op->utils[LDCONFIG], NULL, FALSE, NULL, FALSE);
|
||||
status |= run_command(op, NULL, FALSE, NULL, FALSE,
|
||||
op->utils[LDCONFIG], NULL);
|
||||
|
||||
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, NULL, FALSE);
|
||||
status = run_command(op, NULL, FALSE, NULL, FALSE, cmd, NULL);
|
||||
nvfree(cmd);
|
||||
|
||||
if (status == 0) {
|
||||
@@ -1445,15 +1445,11 @@ int uninstall_existing_driver(Options *op, const int interactive,
|
||||
*/
|
||||
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, NULL, FALSE);
|
||||
|
||||
nvfree(cmd);
|
||||
|
||||
/* exit status is 0 in case of success, so invert here */
|
||||
return !ret;
|
||||
return !run_command(op, NULL, FALSE, NULL, FALSE,
|
||||
uninstaller, " -A | ", op->utils[GREP],
|
||||
" -q '^ \\+--skip-depmod$'", NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -1474,7 +1470,6 @@ int run_existing_uninstaller(Options *op)
|
||||
|
||||
if (uninstaller) {
|
||||
char *uninstall_log_dir, *uninstall_log_file, *uninstall_log_path;
|
||||
char *uninstall_cmd = NULL;
|
||||
char *data = NULL;
|
||||
int ret;
|
||||
|
||||
@@ -1494,21 +1489,19 @@ int run_existing_uninstaller(Options *op)
|
||||
|
||||
/* 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=",
|
||||
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, NULL, TRUE);
|
||||
|
||||
nvfree(uninstall_cmd);
|
||||
ui_status_begin(op, "Uninstalling the previous installation", "");
|
||||
ui_indeterminate_begin(op, "Running `%s...`", uninstaller);
|
||||
ret = run_command(op, &data, FALSE, NULL, TRUE,
|
||||
uninstaller, " -s --log-file-name=",
|
||||
uninstall_log_path,
|
||||
skip_depmod ? " --skip-depmod" : NULL,
|
||||
NULL);
|
||||
ui_indeterminate_end(op);
|
||||
|
||||
/* if nvidia-uninstall succeeded, return early; otherwise, fall back to
|
||||
* uninstalling via the backup log file. */
|
||||
if (ret != 0) {
|
||||
ui_status_end(op, "failed.");
|
||||
ui_log(op, "%s failed; see %s for more details.", uninstaller,
|
||||
uninstall_log_path);
|
||||
if (data && strlen(data)) {
|
||||
@@ -1521,6 +1514,7 @@ int run_existing_uninstaller(Options *op)
|
||||
nvfree(uninstall_log_path);
|
||||
|
||||
if (ret == 0) {
|
||||
ui_status_end(op, "done.");
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
270
command-list.c
270
command-list.c
@@ -45,8 +45,66 @@
|
||||
#include "kernel.h"
|
||||
#include "manifest.h"
|
||||
#include "conflicting-kernel-modules.h"
|
||||
#include "initramfs.h"
|
||||
|
||||
|
||||
/*
|
||||
* commands:
|
||||
*
|
||||
* INSTALL - install the file named in 'path', giving it the name in 'target';
|
||||
* assign 'target' the permissions specified by 'mode'; execute the string in
|
||||
* 'command' as a post-install step
|
||||
*
|
||||
* BACKUP - move the file named in 'path', storing it in the backup
|
||||
* directory and recording the data as appropriate.
|
||||
*
|
||||
* RUN - execute the string in 'command'
|
||||
*
|
||||
* RUN_CMD_LONG - execute the string in 'command' and display an indeterminate
|
||||
* progress bar while it is running.
|
||||
*
|
||||
* SYMLINK - create a symbolic link named 'path', pointing at the filename
|
||||
* specified in 'target'.
|
||||
*
|
||||
* DELETE - delete the file named in 'path'.
|
||||
*
|
||||
* TOUCH_CMD - update the mtime of the path specified in 'path'.
|
||||
*
|
||||
* FUNCTION_CMD - Call the function pointed to by 'function', with a pointer
|
||||
* to the Options structure passed as an argument.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
INVALID_CMD = 0, /* Default value with nvalloc() or memset(..., '0', ...) */
|
||||
INSTALL_CMD,
|
||||
BACKUP_CMD,
|
||||
RUN_CMD,
|
||||
RUN_CMD_LONG,
|
||||
SYMLINK_CMD,
|
||||
DELETE_CMD,
|
||||
TOUCH_CMD,
|
||||
FUNCTION_CMD,
|
||||
} CommandID;
|
||||
|
||||
|
||||
typedef int (*CommandFunction)(Options *);
|
||||
|
||||
|
||||
/*
|
||||
* Command structure - data type for describing what operations to perform
|
||||
* to do an install. Some of the fields may be unset, depending upon the
|
||||
* value of the cmd field (see the constants above).
|
||||
*/
|
||||
|
||||
typedef struct __command {
|
||||
CommandID cmd;
|
||||
char *path;
|
||||
char *target;
|
||||
char *command;
|
||||
mode_t mode;
|
||||
CommandFunction function;
|
||||
} Command;
|
||||
|
||||
static void free_file_list(FileList* l);
|
||||
|
||||
static void find_conflicting_kernel_modules(Options *op, FileList *l);
|
||||
@@ -56,7 +114,7 @@ static void find_existing_files(Package *p, FileList *l,
|
||||
|
||||
static void condense_file_list(Package *p, FileList *l);
|
||||
|
||||
static void add_command (CommandList *c, int cmd, ...);
|
||||
static void add_command (CommandList *c, CommandID cmd, ...);
|
||||
|
||||
static void add_file_to_list(const char*, const char*, FileList*);
|
||||
|
||||
@@ -198,7 +256,8 @@ CommandList *build_command_list(Options *op, Package *p)
|
||||
{
|
||||
FileList *l;
|
||||
CommandList *c;
|
||||
int i, cmd;
|
||||
CommandID cmd;
|
||||
int i;
|
||||
PackageEntryFileTypeList installable_files;
|
||||
PackageEntryFileTypeList tmp_installable_files;
|
||||
char *tmp;
|
||||
@@ -318,7 +377,11 @@ CommandList *build_command_list(Options *op, Package *p)
|
||||
|
||||
for (i = 0; i < l->num; i++)
|
||||
add_command(c, cmd, l->filename[i], NULL, 0);
|
||||
|
||||
|
||||
if (!op->no_kernel_modules) {
|
||||
add_command(c, FUNCTION_CMD, update_initramfs, "Rebuilding initramfs");
|
||||
}
|
||||
|
||||
/* Add all the installable files to the list */
|
||||
|
||||
for (i = 0; i < p->num_entries; i++) {
|
||||
@@ -435,7 +498,7 @@ CommandList *build_command_list(Options *op, Package *p)
|
||||
|
||||
if (!op->no_kernel_modules && !op->skip_depmod) {
|
||||
tmp = nvstrcat(op->utils[DEPMOD], " -a ", op->kernel_name, NULL);
|
||||
add_command(c, RUN_CMD, tmp);
|
||||
add_command(c, RUN_CMD_LONG, tmp);
|
||||
nvfree(tmp);
|
||||
}
|
||||
|
||||
@@ -491,13 +554,15 @@ void free_command_list(Options *op, CommandList *cl)
|
||||
|
||||
for (i = 0; i < cl->num; i++) {
|
||||
c = &cl->cmds[i];
|
||||
if (c->s0) free(c->s0);
|
||||
if (c->s1) free(c->s1);
|
||||
if (c->s2) free(c->s2);
|
||||
free(c->path);
|
||||
free(c->target);
|
||||
free(c->command);
|
||||
free(cl->descriptions[i]);
|
||||
}
|
||||
|
||||
if (cl->cmds) free(cl->cmds);
|
||||
|
||||
free(cl->cmds);
|
||||
free(cl->descriptions);
|
||||
|
||||
free(cl);
|
||||
|
||||
} /* free_command_list() */
|
||||
@@ -506,15 +571,28 @@ void free_command_list(Options *op, CommandList *cl)
|
||||
* execute_run_command() - execute a RUN_CMD from the command list.
|
||||
*/
|
||||
|
||||
#define __RUN_CMD_FORMAT_STRING__ "Executing: %s (this may take a moment...)"
|
||||
|
||||
static inline int execute_run_command(Options *op, float percent, const char *cmd)
|
||||
{
|
||||
int indeterminate = percent < 0;
|
||||
int ret;
|
||||
char *data;
|
||||
|
||||
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, NULL, TRUE);
|
||||
|
||||
if (indeterminate) {
|
||||
ui_indeterminate_begin(op, __RUN_CMD_FORMAT_STRING__, cmd);
|
||||
} else {
|
||||
ui_status_update(op, percent, __RUN_CMD_FORMAT_STRING__, cmd);
|
||||
}
|
||||
|
||||
ret = run_command(op, &data, TRUE, NULL, TRUE, cmd, NULL);
|
||||
|
||||
if (indeterminate) {
|
||||
ui_indeterminate_end(op);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
ui_error(op, "Failed to execute `%s`: %s", cmd, data);
|
||||
ret = continue_after_error(op, "Failed to execute `%s`", cmd);
|
||||
@@ -549,84 +627,96 @@ int execute_command_list(Options *op, CommandList *c,
|
||||
|
||||
case INSTALL_CMD:
|
||||
ui_expert(op, "Installing: %s --> %s",
|
||||
c->cmds[i].s0, c->cmds[i].s1);
|
||||
ui_status_update(op, percent, "Installing: %s", c->cmds[i].s1);
|
||||
c->cmds[i].path, c->cmds[i].target);
|
||||
ui_status_update(op, percent, "Installing: %s", c->cmds[i].target);
|
||||
|
||||
ret = install_file(op, c->cmds[i].s0, c->cmds[i].s1,
|
||||
ret = install_file(op, c->cmds[i].path, c->cmds[i].target,
|
||||
c->cmds[i].mode);
|
||||
if (!ret) {
|
||||
ret = continue_after_error(op, "Cannot install %s",
|
||||
c->cmds[i].s1);
|
||||
c->cmds[i].target);
|
||||
if (!ret) return FALSE;
|
||||
} else {
|
||||
/*
|
||||
* perform post-install step before logging the backup
|
||||
*/
|
||||
if (c->cmds[i].s2 &&
|
||||
!execute_run_command(op, percent, c->cmds[i].s2)) {
|
||||
if (c->cmds[i].command &&
|
||||
!execute_run_command(op, percent, c->cmds[i].command)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
log_install_file(op, c->cmds[i].s1);
|
||||
log_install_file(op, c->cmds[i].target);
|
||||
append_to_rpm_file_list(op, &c->cmds[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case RUN_CMD:
|
||||
if (!execute_run_command(op, percent, c->cmds[i].s0)) {
|
||||
if (!execute_run_command(op, percent, c->cmds[i].command)) {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case RUN_CMD_LONG:
|
||||
if (!execute_run_command(op, c->cmds[i].cmd == RUN_CMD_LONG ? -1 : percent, c->cmds[i].command)) {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case SYMLINK_CMD:
|
||||
ui_expert(op, "Creating symlink: %s -> %s",
|
||||
c->cmds[i].s0, c->cmds[i].s1);
|
||||
c->cmds[i].path, c->cmds[i].target);
|
||||
ui_status_update(op, percent, "Creating symlink: %s",
|
||||
c->cmds[i].s1);
|
||||
c->cmds[i].target);
|
||||
|
||||
ret = install_symlink(op, c->cmds[i].s1, c->cmds[i].s0);
|
||||
ret = install_symlink(op, c->cmds[i].target, c->cmds[i].path);
|
||||
|
||||
if (!ret) {
|
||||
ret = continue_after_error(op, "Cannot create symlink %s (%s)",
|
||||
c->cmds[i].s0, strerror(errno));
|
||||
c->cmds[i].path, strerror(errno));
|
||||
if (!ret) return FALSE;
|
||||
} else {
|
||||
log_create_symlink(op, c->cmds[i].s0, c->cmds[i].s1);
|
||||
log_create_symlink(op, c->cmds[i].path, c->cmds[i].target);
|
||||
}
|
||||
break;
|
||||
|
||||
case BACKUP_CMD:
|
||||
ui_expert(op, "Backing up: %s", c->cmds[i].s0);
|
||||
ui_status_update(op, percent, "Backing up: %s", c->cmds[i].s0);
|
||||
ui_expert(op, "Backing up: %s", c->cmds[i].path);
|
||||
ui_status_update(op, percent, "Backing up: %s", c->cmds[i].path);
|
||||
|
||||
ret = do_backup(op, c->cmds[i].s0);
|
||||
ret = do_backup(op, c->cmds[i].path);
|
||||
if (!ret) {
|
||||
ret = continue_after_error(op, "Cannot backup %s",
|
||||
c->cmds[i].s0);
|
||||
c->cmds[i].path);
|
||||
if (!ret) return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case DELETE_CMD:
|
||||
ui_expert(op, "Deleting: %s", c->cmds[i].s0);
|
||||
ret = unlink(c->cmds[i].s0);
|
||||
ui_expert(op, "Deleting: %s", c->cmds[i].path);
|
||||
ret = unlink(c->cmds[i].path);
|
||||
if (ret == -1) {
|
||||
ret = continue_after_error(op, "Cannot delete %s",
|
||||
c->cmds[i].s0);
|
||||
c->cmds[i].path);
|
||||
if (!ret) return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case TOUCH_CMD:
|
||||
ui_expert(op, "Updating mtime: %s", c->cmds[i].s0);
|
||||
ret = utime(c->cmds[i].s0, NULL);
|
||||
ui_expert(op, "Updating mtime: %s", c->cmds[i].path);
|
||||
ret = utime(c->cmds[i].path, NULL);
|
||||
if (ret == -1) {
|
||||
ret = continue_after_error(op, "Cannot touch %s",
|
||||
c->cmds[i].s0);
|
||||
c->cmds[i].path);
|
||||
if (!ret) return FALSE;
|
||||
}
|
||||
break;
|
||||
case FUNCTION_CMD:
|
||||
ui_expert(op, "%s:", c->descriptions[i]);
|
||||
ret = c->cmds[i].function(op);
|
||||
if (!ret) {
|
||||
ret = continue_after_error(op, "%s failed", c->descriptions[i]);
|
||||
if (!ret) return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* XXX should never get here */
|
||||
return FALSE;
|
||||
@@ -1041,55 +1131,105 @@ static void condense_file_list(Package *p, FileList *l)
|
||||
|
||||
|
||||
|
||||
static char *get_command_description(const Command *c)
|
||||
{
|
||||
char *ret = NULL;
|
||||
char *perms;
|
||||
|
||||
switch (c->cmd) {
|
||||
case INSTALL_CMD:
|
||||
perms = mode_to_permission_string(c->mode);
|
||||
ret = nvasprintf("Install the file '%s' as '%s' with permissions '%s'",
|
||||
c->path, c->target, perms);
|
||||
if (c->command) {
|
||||
char *newret = nvstrcat(ret, " then execute the command `",
|
||||
c->command, "`", NULL);
|
||||
nvfree(ret);
|
||||
ret = newret;
|
||||
}
|
||||
nvfree(perms);
|
||||
break;
|
||||
|
||||
case RUN_CMD:
|
||||
ret = nvasprintf("Execute the command `%s`", c->command);
|
||||
break;
|
||||
|
||||
case SYMLINK_CMD:
|
||||
ret = nvasprintf("Create a symbolic link '%s' to '%s'",
|
||||
c->path, c->target);
|
||||
break;
|
||||
|
||||
case BACKUP_CMD:
|
||||
ret = nvasprintf("Back up the file '%s'", c->path);
|
||||
break;
|
||||
|
||||
case DELETE_CMD:
|
||||
ret = nvasprintf("Delete the file '%s'", c->path);
|
||||
break;
|
||||
|
||||
case FUNCTION_CMD:
|
||||
/* FUNCTION_CMD descriptions get set by the caller */
|
||||
break;
|
||||
|
||||
default:
|
||||
/* XXX should not get here */
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* add_command() - grow the commandlist and append the new command,
|
||||
* parsing the variable argument list.
|
||||
*/
|
||||
|
||||
static void add_command(CommandList *c, int cmd, ...)
|
||||
static void add_command(CommandList *c, CommandID cmd, ...)
|
||||
{
|
||||
int n = c->num;
|
||||
char *s;
|
||||
va_list ap;
|
||||
|
||||
c->cmds = (Command *) nvrealloc(c->cmds, sizeof(Command) * (n + 1));
|
||||
|
||||
c->descriptions = nvrealloc(c->descriptions, sizeof(char *) * (n + 1));
|
||||
|
||||
memset(c->cmds + n, 0, sizeof(Command));
|
||||
c->cmds[n].cmd = cmd;
|
||||
c->cmds[n].s0 = NULL;
|
||||
c->cmds[n].s1 = NULL;
|
||||
c->cmds[n].s2 = NULL;
|
||||
c->cmds[n].mode = 0x0;
|
||||
|
||||
c->descriptions[n] = NULL;
|
||||
|
||||
va_start(ap, cmd);
|
||||
|
||||
switch (cmd) {
|
||||
case INSTALL_CMD:
|
||||
s = va_arg(ap, char *);
|
||||
c->cmds[n].s0 = nvstrdup(s);
|
||||
s = va_arg(ap, char *);
|
||||
c->cmds[n].s1 = nvstrdup(s);
|
||||
s = va_arg(ap, char *);
|
||||
c->cmds[n].s2 = nvstrdup(s);
|
||||
c->cmds[n].mode = va_arg(ap, mode_t);
|
||||
break;
|
||||
case BACKUP_CMD:
|
||||
s = va_arg(ap, char *);
|
||||
c->cmds[n].s0 = nvstrdup(s);
|
||||
break;
|
||||
case RUN_CMD:
|
||||
s = va_arg(ap, char *);
|
||||
c->cmds[n].s0 = nvstrdup(s);
|
||||
break;
|
||||
case SYMLINK_CMD:
|
||||
s = va_arg(ap, char *);
|
||||
c->cmds[n].s0 = nvstrdup(s);
|
||||
c->cmds[n].path = nvstrdup(s);
|
||||
s = va_arg(ap, char *);
|
||||
c->cmds[n].s1 = nvstrdup(s);
|
||||
c->cmds[n].target = nvstrdup(s);
|
||||
|
||||
if (cmd == INSTALL_CMD) {
|
||||
s = va_arg(ap, char *);
|
||||
c->cmds[n].command = nvstrdup(s);
|
||||
c->cmds[n].mode = va_arg(ap, mode_t);
|
||||
}
|
||||
|
||||
break;
|
||||
case BACKUP_CMD:
|
||||
case DELETE_CMD:
|
||||
case TOUCH_CMD:
|
||||
s = va_arg(ap, char *);
|
||||
c->cmds[n].s0 = nvstrdup(s);
|
||||
c->cmds[n].path = nvstrdup(s);
|
||||
break;
|
||||
case RUN_CMD:
|
||||
case RUN_CMD_LONG:
|
||||
s = va_arg(ap, char *);
|
||||
c->cmds[n].command = nvstrdup(s);
|
||||
break;
|
||||
case FUNCTION_CMD:
|
||||
c->cmds[n].function = va_arg(ap, CommandFunction);
|
||||
s = va_arg(ap, char *);
|
||||
c->descriptions[n] = nvstrdup(s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -1097,6 +1237,10 @@ static void add_command(CommandList *c, int cmd, ...)
|
||||
|
||||
va_end(ap);
|
||||
|
||||
if (!c->descriptions[n]) {
|
||||
c->descriptions[n] = get_command_description(c->cmds + n);
|
||||
}
|
||||
|
||||
c->num++;
|
||||
|
||||
} /* add_command() */
|
||||
@@ -1135,6 +1279,6 @@ static void append_to_rpm_file_list(Options *op, Command *c)
|
||||
if (!op->rpm_file_list) return;
|
||||
|
||||
file = fopen(op->rpm_file_list, "a");
|
||||
fprintf(file, "%%attr (%04o, root, root) %s\n", c->mode, c->s1);
|
||||
fprintf(file, "%%attr (%04o, root, root) %s\n", c->mode, c->target);
|
||||
fclose(file);
|
||||
}
|
||||
|
@@ -20,25 +20,16 @@
|
||||
#ifndef __NVIDIA_INSTALLER_COMMAND_LIST_H__
|
||||
#define __NVIDIA_INSTALLER_COMMAND_LIST_H__
|
||||
|
||||
|
||||
/*
|
||||
* Command and CommandList structures - data types for describing what
|
||||
* operations to perform to do an install. The semantics of the s0,
|
||||
* s1, and mode fields vary, depending upon the value of the cmd field
|
||||
* (see the constants below).
|
||||
* List of commands to process. Each command has a description which can
|
||||
* be accessed by command list clients; the actual command structure which
|
||||
* gets processed is opaque.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
int cmd;
|
||||
char *s0;
|
||||
char *s1;
|
||||
char *s2;
|
||||
mode_t mode;
|
||||
} Command;
|
||||
|
||||
typedef struct {
|
||||
int num;
|
||||
Command *cmds;
|
||||
char **descriptions;
|
||||
struct __command *cmds;
|
||||
} CommandList;
|
||||
|
||||
|
||||
@@ -52,33 +43,6 @@ typedef struct {
|
||||
} FileList;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* commands:
|
||||
*
|
||||
* INSTALL - install the file named is s0, giving it the name in s1;
|
||||
* assign s1 the permissions specified by mode; execute the string in s2 as a
|
||||
* post-install step
|
||||
*
|
||||
* BACKUP - move the file named in s0, storing it in the backup
|
||||
* directory and recording the data as appropriate.
|
||||
*
|
||||
* RUN - execute the string in s0
|
||||
*
|
||||
* SYMLINK - create a symbolic link named s0, pointing at the filename
|
||||
* specified in s1.
|
||||
*
|
||||
* TOUCH_CMD - update the mtime of the path specified in s0.
|
||||
*/
|
||||
|
||||
#define INSTALL_CMD 1
|
||||
#define BACKUP_CMD 2
|
||||
#define RUN_CMD 3
|
||||
#define SYMLINK_CMD 4
|
||||
#define DELETE_CMD 5
|
||||
#define TOUCH_CMD 6
|
||||
|
||||
|
||||
CommandList *build_command_list(Options*, Package *);
|
||||
void free_command_list(Options*, CommandList*);
|
||||
int execute_command_list(Options*, CommandList*, const char*, const char*);
|
||||
|
@@ -65,26 +65,26 @@ void *nvalloc(size_t size)
|
||||
|
||||
|
||||
/*
|
||||
* nvstrcat() - allocate a new string, copying all given strings
|
||||
* nvvstrcat() - allocate a new string, copying all given strings
|
||||
* into it.
|
||||
*/
|
||||
|
||||
char *nvstrcat(const char *str, ...)
|
||||
char *nvvstrcat(const char *str, va_list ap)
|
||||
{
|
||||
const char *s;
|
||||
char *result;
|
||||
size_t len;
|
||||
va_list ap;
|
||||
va_list ap2;
|
||||
|
||||
/* walk the varargs to compute the length of the result string */
|
||||
|
||||
va_start(ap, str);
|
||||
va_copy(ap2, ap);
|
||||
|
||||
for (s = str, len = 1; s; s = va_arg(ap, char *)) {
|
||||
for (s = str, len = 1; s; s = va_arg(ap2, char *)) {
|
||||
len += strlen(s);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
va_end(ap2);
|
||||
|
||||
/* allocate the result string */
|
||||
|
||||
@@ -96,18 +96,30 @@ char *nvstrcat(const char *str, ...)
|
||||
|
||||
/* concatenate the input strings, writing into the result string */
|
||||
|
||||
va_start(ap, str);
|
||||
|
||||
for (s = str; s; s = va_arg(ap, char *)) {
|
||||
strcat(result, s);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
return result;
|
||||
} /* nvstrcat() */
|
||||
|
||||
|
||||
/*
|
||||
* nvstrcat() - allocate a new string, copying all given strings
|
||||
* into it.
|
||||
*/
|
||||
|
||||
char *nvstrcat(const char *str, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *ret;
|
||||
|
||||
va_start(ap, str);
|
||||
ret = nvvstrcat(str, ap);
|
||||
va_end(ap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* nvrealloc() - realloc wrapper that checks for errors; if an error
|
||||
|
@@ -53,6 +53,7 @@
|
||||
|
||||
void *nvalloc(size_t size);
|
||||
char *nvstrcat(const char *str, ...);
|
||||
char *nvvstrcat(const char *str, va_list ap);
|
||||
void *nvrealloc(void *ptr, size_t size);
|
||||
char *nvstrdup(const char *s);
|
||||
char *nvstrndup(const char *s, size_t n);
|
||||
|
@@ -44,7 +44,7 @@
|
||||
|
||||
static NvVerbosity __verbosity = NV_VERBOSITY_DEFAULT;
|
||||
|
||||
NvVerbosity nv_get_verbosity()
|
||||
NvVerbosity nv_get_verbosity(void)
|
||||
{
|
||||
return __verbosity;
|
||||
}
|
||||
|
@@ -41,6 +41,8 @@ SRC += user-interface.c
|
||||
SRC += sanity.c
|
||||
SRC += manifest.c
|
||||
SRC += conflicting-kernel-modules.c
|
||||
SRC += initramfs.c
|
||||
SRC += ui-status-indeterminate.c
|
||||
|
||||
DIST_FILES := $(SRC)
|
||||
|
||||
@@ -58,6 +60,8 @@ DIST_FILES += sanity.h
|
||||
DIST_FILES += user-interface.h
|
||||
DIST_FILES += manifest.h
|
||||
DIST_FILES += conflicting-kernel-modules.h
|
||||
DIST_FILES += initramfs.h
|
||||
DIST_FILES += ui-status-indeterminate.h
|
||||
|
||||
DIST_FILES += COPYING
|
||||
DIST_FILES += README
|
||||
|
113
files.c
113
files.c
@@ -43,6 +43,7 @@
|
||||
#include "misc.h"
|
||||
#include "precompiled.h"
|
||||
#include "backup.h"
|
||||
#include "kernel.h"
|
||||
|
||||
|
||||
static void get_x_library_and_module_paths(Options *op);
|
||||
@@ -227,7 +228,17 @@ int copy_file(Options *op, const char *srcfile,
|
||||
srcfile, strerror (errno));
|
||||
goto done;
|
||||
}
|
||||
if ((dst_fd = open(dstfile, O_RDWR | O_CREAT | O_TRUNC, mode)) == -1) {
|
||||
if (stat(dstfile, &stat_buf) == 0) {
|
||||
/* Unlink any existing destination file first, to ensure that the
|
||||
destination file will be newly created, rather than overwriting
|
||||
the contents of a file which may be in use by another program. */
|
||||
if (unlink(dstfile) == -1 && errno != ENOENT) {
|
||||
ui_error (op, "Unable to delete existing file '%s' (%s)",
|
||||
dstfile, strerror (errno));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if ((dst_fd = open(dstfile, O_RDWR | O_CREAT, mode)) == -1) {
|
||||
ui_error (op, "Unable to create '%s' for copying (%s)",
|
||||
dstfile, strerror (errno));
|
||||
goto done;
|
||||
@@ -1613,7 +1624,7 @@ int check_for_existing_rpms(Options *op)
|
||||
|
||||
const char *rpms[2] = { "NVIDIA_GLX", "NVIDIA_kernel" };
|
||||
|
||||
char *data, *cmd;
|
||||
char *data;
|
||||
int i, ret;
|
||||
|
||||
if (op->no_rpms) {
|
||||
@@ -1622,11 +1633,9 @@ int check_for_existing_rpms(Options *op)
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
|
||||
cmd = nvstrcat("env LD_KERNEL_ASSUME=2.2.5 rpm --query ",
|
||||
rpms[i], NULL);
|
||||
ret = run_command(op, cmd, NULL, FALSE, NULL, TRUE);
|
||||
nvfree(cmd);
|
||||
ret = run_command(op, NULL, FALSE, NULL, TRUE,
|
||||
"env LD_KERNEL_ASSUME=2.2.5 rpm --query ",
|
||||
rpms[i], NULL);
|
||||
|
||||
if (ret == 0) {
|
||||
if (ui_multiple_choice(op, CONTINUE_ABORT_CHOICES,
|
||||
@@ -1641,11 +1650,10 @@ int check_for_existing_rpms(Options *op)
|
||||
ui_log(op, "Installation aborted.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
cmd = nvstrcat("rpm --erase --nodeps ", rpms[i], NULL);
|
||||
ret = run_command(op, cmd, &data, op->expert, NULL, TRUE);
|
||||
nvfree(cmd);
|
||||
|
||||
|
||||
ret = run_command(op, &data, op->expert, NULL, TRUE,
|
||||
"rpm --erase --nodeps ", rpms[i], NULL);
|
||||
|
||||
if (ret == 0) {
|
||||
ui_log(op, "Removed %s.", rpms[i]);
|
||||
} else {
|
||||
@@ -1736,21 +1744,20 @@ int pack_precompiled_files(Options *op, Package *p, int num_files,
|
||||
PrecompiledFileInfo *files)
|
||||
{
|
||||
char time_str[256], *proc_version_string;
|
||||
char *outfile, *descr;
|
||||
char *outfile = NULL, *descr = NULL;
|
||||
char *precompiled_dir = precompiled_kernel_interface_path(p);
|
||||
time_t t;
|
||||
struct utsname buf;
|
||||
int ret;
|
||||
PrecompiledInfo *info;
|
||||
int ret = FALSE;
|
||||
PrecompiledInfo *info = NULL;
|
||||
|
||||
ui_log(op, "Packaging precompiled kernel interface.");
|
||||
|
||||
/* make sure the precompiled_kernel_interface_directory exists */
|
||||
/* make sure the precompiled kernel interface directory exists */
|
||||
|
||||
if (!mkdir_recursive(op, p->precompiled_kernel_interface_directory, 0755,
|
||||
FALSE)) {
|
||||
ui_error(op, "Failed to create the directory '%s'!",
|
||||
p->precompiled_kernel_interface_directory);
|
||||
return FALSE;
|
||||
if (!mkdir_recursive(op, precompiled_dir, 0755, FALSE)) {
|
||||
ui_error(op, "Failed to create the directory '%s'!", precompiled_dir);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* use the time in the output string... should be fairly unique */
|
||||
@@ -1777,7 +1784,7 @@ int pack_precompiled_files(Options *op, Package *p, int num_files,
|
||||
|
||||
info = nvalloc(sizeof(PrecompiledInfo));
|
||||
|
||||
outfile = nvstrcat(p->precompiled_kernel_interface_directory, "/",
|
||||
outfile = nvstrcat(precompiled_dir, "/",
|
||||
PRECOMPILED_PACKAGE_FILENAME, "-", p->version,
|
||||
".", time_str, NULL);
|
||||
|
||||
@@ -1789,17 +1796,17 @@ int pack_precompiled_files(Options *op, Package *p, int num_files,
|
||||
|
||||
ret = precompiled_pack(info, outfile);
|
||||
|
||||
done:
|
||||
|
||||
nvfree(precompiled_dir);
|
||||
nvfree(outfile);
|
||||
free_precompiled(info);
|
||||
|
||||
if (ret) {
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
/* XXX precompiled_pack() never fails */
|
||||
if (!ret) {
|
||||
ui_error(op, "Unable to package precompiled kernel interface.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -2167,25 +2174,24 @@ void process_dkms_conf(Options *op, Package *p)
|
||||
|
||||
/*
|
||||
* set_security_context() - set the security context of the file to 'type'
|
||||
* Returns TRUE on success or if SELinux is disabled, FALSE otherwise
|
||||
* Returns TRUE on success or if SELinux is disabled, FALSE otherwise.
|
||||
* This relies on chcon(1), which might not work on some idiosyncratic
|
||||
* systems: a possible alternative would be to directly use the xattr(7)
|
||||
* API, but for now, chcon(1) is better for abstracting away the intimate
|
||||
* details of the "security.selinux" xattr format. (See bug 3876232)
|
||||
*/
|
||||
int set_security_context(Options *op, const char *filename, const char *type)
|
||||
{
|
||||
char *cmd = NULL;
|
||||
int ret = FALSE;
|
||||
|
||||
if (op->selinux_enabled == FALSE) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cmd = nvstrcat(op->utils[CHCON], " -t ", type, " ", filename, NULL);
|
||||
|
||||
ret = run_command(op, cmd, NULL, FALSE, NULL, TRUE);
|
||||
|
||||
ret = ((ret == 0) ? TRUE : FALSE);
|
||||
nvfree(cmd);
|
||||
|
||||
return ret;
|
||||
|
||||
ret = run_command(op, NULL, FALSE, NULL, TRUE,
|
||||
op->utils[CHCON], " -t ", type, " ", filename, NULL);
|
||||
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -2238,12 +2244,11 @@ static char * const compat_libdirs[] = {
|
||||
|
||||
static char *get_ldconfig_cache(Options *op)
|
||||
{
|
||||
char *data, *cmd;
|
||||
char *data;
|
||||
int ret;
|
||||
|
||||
cmd = nvstrcat(op->utils[LDCONFIG], " -p", NULL);
|
||||
ret = run_command(op, cmd, &data, FALSE, NULL, FALSE);
|
||||
nvfree(cmd);
|
||||
ret = run_command(op, &data, FALSE, NULL, FALSE,
|
||||
op->utils[LDCONFIG], " -p", NULL);
|
||||
|
||||
if (ret != 0) {
|
||||
nvfree(data);
|
||||
@@ -2618,7 +2623,7 @@ static int get_x_paths_helper(Options *op,
|
||||
char **path,
|
||||
int require_existing_directory)
|
||||
{
|
||||
char *dirs, *cmd, *dir, *next;
|
||||
char *dirs, *dir, *next;
|
||||
int ret, guessed = 0;
|
||||
|
||||
/*
|
||||
@@ -2641,9 +2646,8 @@ static int get_x_paths_helper(Options *op,
|
||||
if (op->utils[XSERVER] && xserver_cmd) {
|
||||
|
||||
dirs = NULL;
|
||||
cmd = nvstrcat(op->utils[XSERVER], " ", xserver_cmd, NULL);
|
||||
ret = run_command(op, cmd, &dirs, FALSE, NULL, TRUE);
|
||||
nvfree(cmd);
|
||||
ret = run_command(op, &dirs, FALSE, NULL, TRUE,
|
||||
op->utils[XSERVER], " ", xserver_cmd, NULL);
|
||||
|
||||
if ((ret == 0) && dirs) {
|
||||
|
||||
@@ -2687,10 +2691,8 @@ static int get_x_paths_helper(Options *op,
|
||||
if (op->utils[PKG_CONFIG]) {
|
||||
|
||||
dirs = NULL;
|
||||
cmd = nvstrcat(op->utils[PKG_CONFIG], " ",
|
||||
pkg_config_cmd, NULL);
|
||||
ret = run_command(op, cmd, &dirs, FALSE, NULL, TRUE);
|
||||
nvfree(cmd);
|
||||
ret = run_command(op, &dirs, FALSE, NULL, TRUE,
|
||||
op->utils[PKG_CONFIG], " ", pkg_config_cmd, NULL);
|
||||
|
||||
if ((ret == 0) && dirs) {
|
||||
|
||||
@@ -2876,7 +2878,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, NULL, TRUE);
|
||||
ret = run_command(op, NULL, FALSE, NULL, TRUE, cmdline, NULL);
|
||||
log_printf(op, NULL, "%s: %s", cmdline, ret == 0 ? "" : "failed!");
|
||||
|
||||
nvfree(cmd);
|
||||
@@ -3072,7 +3074,7 @@ static LibglvndInstallCheckResult run_libglvnd_script(Options *op, Package *p,
|
||||
char **missing_libs)
|
||||
{
|
||||
const char *scriptPath = "./libglvnd_install_checker/check-libglvnd-install.sh";
|
||||
char *cmdline = NULL, *output = NULL;
|
||||
char *output = NULL;
|
||||
int status;
|
||||
LibglvndInstallCheckResult result = LIBGLVND_CHECK_RESULT_ERROR;
|
||||
|
||||
@@ -3089,8 +3091,8 @@ static LibglvndInstallCheckResult run_libglvnd_script(Options *op, Package *p,
|
||||
goto done;
|
||||
}
|
||||
|
||||
cmdline = nvasprintf("/bin/sh %s", scriptPath);
|
||||
status = run_command(op, cmdline, &output, TRUE, NULL, FALSE);
|
||||
status = run_command(op, &output, TRUE, NULL, FALSE,
|
||||
"/bin/sh ", scriptPath, NULL);
|
||||
if (WIFEXITED(status)) {
|
||||
result = WEXITSTATUS(status);
|
||||
} else {
|
||||
@@ -3124,7 +3126,6 @@ static LibglvndInstallCheckResult run_libglvnd_script(Options *op, Package *p,
|
||||
|
||||
done:
|
||||
nvfree(output);
|
||||
nvfree(cmdline);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
651
initramfs.c
Normal file
651
initramfs.c
Normal file
@@ -0,0 +1,651 @@
|
||||
/*
|
||||
* Copyright (C) 2023 NVIDIA Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "nvidia-installer.h"
|
||||
#include "user-interface.h"
|
||||
#include "kernel.h"
|
||||
#include "initramfs.h"
|
||||
#include "misc.h"
|
||||
#include "conflicting-kernel-modules.h"
|
||||
|
||||
/*
|
||||
* get_initramfs_path() - Test well-known locations for the existence of
|
||||
* candidate initramfs files. If there is more than one candidate, prompt the
|
||||
* user to select one of them. Returns the found (if one) or selected (if more
|
||||
* than one found) file, or NULL if no file is found or the user declines to
|
||||
* select one.
|
||||
*/
|
||||
|
||||
static char *get_initramfs_path(Options *op)
|
||||
{
|
||||
static char *path_ret;
|
||||
static int attempted;
|
||||
char *kernel_name;
|
||||
|
||||
if (attempted) {
|
||||
/* This function has already been called: return the cached path value
|
||||
* (which may be NULL if no path was found previously). */
|
||||
|
||||
return path_ret;
|
||||
}
|
||||
|
||||
kernel_name = get_kernel_name(op);
|
||||
if (kernel_name) {
|
||||
int num_found_paths = 0, found_paths_size = 8;
|
||||
int i;
|
||||
char **found_paths = nvalloc(found_paths_size * sizeof(char*));
|
||||
char *tmp;
|
||||
|
||||
#define __TEST_INITRAMFS_FILE(format, str) { \
|
||||
char *path = nvasprintf("/boot/" format, str); \
|
||||
if (access(path, F_OK) == 0) { \
|
||||
if (num_found_paths + 2 > found_paths_size) { \
|
||||
found_paths_size *= 2; \
|
||||
found_paths = nvrealloc(found_paths, \
|
||||
found_paths_size * sizeof(char*)); \
|
||||
} \
|
||||
found_paths[num_found_paths++] = path; \
|
||||
} else { \
|
||||
nvfree(path); \
|
||||
} \
|
||||
}
|
||||
|
||||
__TEST_INITRAMFS_FILE("initramfs-%s.img", kernel_name);
|
||||
__TEST_INITRAMFS_FILE("initramfs-%s.img", "linux");
|
||||
__TEST_INITRAMFS_FILE("initramfs-%s.img", "linux-lts");
|
||||
__TEST_INITRAMFS_FILE("initrd-%s", kernel_name);
|
||||
__TEST_INITRAMFS_FILE("initrd.img-%s", kernel_name);
|
||||
|
||||
tmp = strchr(kernel_name, '.');
|
||||
if (tmp) {
|
||||
char *kernel_name_copy = strdup(kernel_name);
|
||||
|
||||
if (kernel_name_copy) {
|
||||
tmp = strchr(kernel_name_copy, '.');
|
||||
if (tmp) {
|
||||
tmp = strchr(tmp + 1, '.');
|
||||
}
|
||||
if (tmp) {
|
||||
char *linux_ver_arch;
|
||||
|
||||
tmp[0] = '\0';
|
||||
linux_ver_arch = nvstrcat("linux-", kernel_name_copy, "-",
|
||||
get_machine_arch(op), NULL);
|
||||
__TEST_INITRAMFS_FILE("initramfs-%s.img", linux_ver_arch);
|
||||
nvfree(linux_ver_arch);
|
||||
}
|
||||
}
|
||||
|
||||
nvfree(kernel_name_copy);
|
||||
}
|
||||
|
||||
if (num_found_paths == 1) {
|
||||
path_ret = found_paths[0];
|
||||
} else if (num_found_paths > 1) {
|
||||
int answer;
|
||||
|
||||
/* We ensured we have enough space in __TEST_INITRAMFS_FILE() */
|
||||
found_paths[num_found_paths] = "Use none of these";
|
||||
|
||||
answer = ui_multiple_choice(op, (const char * const*)found_paths,
|
||||
num_found_paths + 1, num_found_paths,
|
||||
"More than one initramfs file found. "
|
||||
"Which file would you like to use?");
|
||||
if (answer < num_found_paths) {
|
||||
/* answer == found_paths means the user opted out */
|
||||
path_ret = found_paths[answer];
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean up the paths that we're not returning */
|
||||
for (i = 0; i < num_found_paths; i++) {
|
||||
if (found_paths[i] != path_ret) {
|
||||
nvfree(found_paths[i]);
|
||||
}
|
||||
}
|
||||
nvfree(found_paths);
|
||||
|
||||
}
|
||||
attempted = TRUE;
|
||||
|
||||
return path_ret;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
INITRAMFS_LIST_TOOL,
|
||||
INITRAMFS_REBUILD_TOOL,
|
||||
} InitramfsToolType;
|
||||
|
||||
char *initramfs_tool_purpose[] = {
|
||||
[INITRAMFS_LIST_TOOL] = "listing initramfs contents",
|
||||
[INITRAMFS_REBUILD_TOOL] = "rebuilding initramfs",
|
||||
};
|
||||
|
||||
/* Table of known initramfs tools and their arguments */
|
||||
static struct initramfs_tool {
|
||||
/* Purpose of the tool (listing, rebuilding, etc.) */
|
||||
InitramfsToolType type;
|
||||
/* Name of the tool */
|
||||
const char *name;
|
||||
/* Arguments that are always set, for the purposes of nvidia-installer
|
||||
* using the tool. */
|
||||
const char *common_args;
|
||||
/* Arguments that are set when a kernel version is specified. These
|
||||
* arguments precede the kernel version. Set to NULL if the tool does
|
||||
* not accept kernel versions on its command line. */
|
||||
const char *kernel_specific_args;
|
||||
/* Indicates whether kernel version must be specified with this tool */
|
||||
int requires_kernel;
|
||||
/* Arguments that are set when an initramfs file is specified. These
|
||||
* arguments precede the path. Set to NULL if the tool does not accept
|
||||
* an initramfs file path on its command line. */
|
||||
const char *path_specific_args;
|
||||
/* Indicates whether initramfs path must be specified with this tool */
|
||||
int requires_path;
|
||||
} initramfs_tools[] = {
|
||||
{
|
||||
.type = INITRAMFS_LIST_TOOL,
|
||||
.name = "lsinitramfs",
|
||||
.common_args = "",
|
||||
.kernel_specific_args = NULL,
|
||||
.requires_kernel = FALSE,
|
||||
.path_specific_args = "-l",
|
||||
.requires_path = TRUE,
|
||||
},
|
||||
{
|
||||
.type = INITRAMFS_LIST_TOOL,
|
||||
.name = "lsinitrd",
|
||||
.common_args = "",
|
||||
.kernel_specific_args = "-k",
|
||||
.requires_kernel = FALSE,
|
||||
.path_specific_args = "",
|
||||
.requires_path = FALSE,
|
||||
},
|
||||
{
|
||||
.type = INITRAMFS_LIST_TOOL,
|
||||
.name = "lsinitcpio",
|
||||
.common_args = "",
|
||||
.kernel_specific_args = NULL,
|
||||
.requires_kernel = FALSE,
|
||||
.path_specific_args = "",
|
||||
.requires_path = TRUE,
|
||||
},
|
||||
{
|
||||
.type = INITRAMFS_REBUILD_TOOL,
|
||||
.name = "dracut",
|
||||
.common_args = "--force",
|
||||
.kernel_specific_args = "--kver",
|
||||
.requires_kernel = FALSE,
|
||||
.path_specific_args = "",
|
||||
.requires_path = FALSE,
|
||||
},
|
||||
{
|
||||
.type = INITRAMFS_REBUILD_TOOL,
|
||||
.name = "update-initramfs",
|
||||
.common_args = "-u",
|
||||
.kernel_specific_args = "-k",
|
||||
.requires_kernel = FALSE,
|
||||
.path_specific_args = NULL,
|
||||
.requires_path = FALSE,
|
||||
},
|
||||
{
|
||||
.type = INITRAMFS_REBUILD_TOOL,
|
||||
.name = "mkinitcpio",
|
||||
.common_args = "-P",
|
||||
.kernel_specific_args = "",
|
||||
.requires_kernel = FALSE,
|
||||
.path_specific_args = "",
|
||||
.requires_path = FALSE,
|
||||
},
|
||||
};
|
||||
|
||||
typedef struct initramfs_tool InitramfsTool;
|
||||
|
||||
static int get_tool_index(Options *op, const InitramfsTool *tool)
|
||||
{
|
||||
if (tool->requires_kernel && get_kernel_name(op) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tool->requires_path && get_initramfs_path(op) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return tool - initramfs_tools;
|
||||
}
|
||||
|
||||
enum {
|
||||
NON_INTERACTIVE,
|
||||
INTERACTIVE,
|
||||
};
|
||||
|
||||
/* find_initramfs_tool() - Attempt to locate a tool of the given type.
|
||||
* Returns the index to the found tool's entry in the initramfs_tools[] table,
|
||||
* if exactly one matching tool is found. If more than one tool is found and
|
||||
* interactive is set, the user will be prompted to select one of the found
|
||||
* tools. Returns the index to the found or selected tool, or -1 if no tool is
|
||||
* found, or if a multiple-tool situation is unresolved, either by user choice
|
||||
* or when running in non-interactive mode. */
|
||||
static int find_initramfs_tool(Options *op, InitramfsToolType type,
|
||||
int interactive)
|
||||
{
|
||||
InitramfsTool *found_tools[ARRAY_LEN(initramfs_tools)];
|
||||
const char *purpose = initramfs_tool_purpose[type];
|
||||
int i, num_found_tools = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_LEN(initramfs_tools); i++) {
|
||||
if (initramfs_tools[i].type != type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (find_system_util(initramfs_tools[i].name)) {
|
||||
found_tools[num_found_tools++] = initramfs_tools + i;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_found_tools == 0) {
|
||||
ui_log(op, "Unable to locate any tools for %s.", purpose);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (num_found_tools == 1) {
|
||||
return get_tool_index(op, found_tools[0]);
|
||||
} else if (interactive == NON_INTERACTIVE) {
|
||||
return -1;
|
||||
} else {
|
||||
const char *found_tool_names[num_found_tools + 1];
|
||||
int chosen_tool;
|
||||
|
||||
for (i = 0; i < num_found_tools; i++) {
|
||||
found_tool_names[i] = found_tools[i]->name;
|
||||
}
|
||||
|
||||
found_tool_names[num_found_tools] = "None of these";
|
||||
|
||||
chosen_tool = ui_multiple_choice(op, found_tool_names,
|
||||
num_found_tools + 1, num_found_tools,
|
||||
"More than one tool for %s detected. "
|
||||
"Which tool would you like to use?",
|
||||
purpose);
|
||||
|
||||
if (chosen_tool == num_found_tools) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return get_tool_index(op, found_tools[chosen_tool]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* initramfs_tool_helper() - run the specified tool with the given kernel and
|
||||
* initramfs file path arguments.
|
||||
*/
|
||||
static int initramfs_tool_helper(Options *op, int tool, const char *kernel,
|
||||
const char *path, char **data, int interactive)
|
||||
{
|
||||
char *cmd, *tool_path, *kernel_args, *path_args, *buf, **cmd_data;
|
||||
int standalone = !op->ui.status_active;
|
||||
int ret = 1;
|
||||
|
||||
if (data) {
|
||||
cmd_data = data;
|
||||
} else {
|
||||
cmd_data = &buf;
|
||||
}
|
||||
|
||||
*cmd_data = NULL;
|
||||
|
||||
tool_path = find_system_util(initramfs_tools[tool].name);
|
||||
kernel_args = path_args = NULL;
|
||||
|
||||
/* Build kernel version specific command line arguments */
|
||||
if (kernel) {
|
||||
if (!initramfs_tools[tool].kernel_specific_args) {
|
||||
ui_log(op, "%s does not take a kernel argument.", tool_path);
|
||||
goto done;
|
||||
}
|
||||
kernel_args = nvstrcat(initramfs_tools[tool].kernel_specific_args, " ",
|
||||
kernel, NULL);
|
||||
} else {
|
||||
if (initramfs_tools[tool].requires_kernel) {
|
||||
ui_log(op, "%s requires a kernel argument, but none was given.",
|
||||
tool_path);
|
||||
goto done;
|
||||
}
|
||||
kernel_args = nvstrdup("");
|
||||
}
|
||||
|
||||
/* Build initramfs file path specific command line arguments */
|
||||
if (path && initramfs_tools[tool].path_specific_args) {
|
||||
if (!initramfs_tools[tool].path_specific_args) {
|
||||
ui_log(op, "%s does not take a path argument.", tool_path);
|
||||
goto done;
|
||||
}
|
||||
path_args = nvstrcat(initramfs_tools[tool].path_specific_args, " ",
|
||||
path, NULL);
|
||||
} else {
|
||||
if (initramfs_tools[tool].requires_path || !path) {
|
||||
ui_log(op, "%s requires a file path argument, but none was given.",
|
||||
tool_path);
|
||||
goto done;
|
||||
}
|
||||
path_args = nvstrdup("");
|
||||
}
|
||||
|
||||
/* Combine arguments into full command line. */
|
||||
cmd = nvstrcat(tool_path, " ", initramfs_tools[tool].common_args, " ",
|
||||
kernel_args, " ", path_args, NULL);
|
||||
|
||||
if (interactive) {
|
||||
const char *s = initramfs_tool_purpose[initramfs_tools[tool].type];
|
||||
|
||||
if (standalone) {
|
||||
ui_status_begin(op, "Processing the initramfs:", "%s", s);
|
||||
}
|
||||
|
||||
ui_indeterminate_begin(op, "%s (this may take a while)", s);
|
||||
}
|
||||
|
||||
ui_log(op, "Executing: %s", cmd);
|
||||
ret = run_command(op, cmd_data, FALSE, NULL, TRUE, cmd, NULL);
|
||||
|
||||
if (interactive) {
|
||||
ui_indeterminate_end(op);
|
||||
|
||||
if (standalone) {
|
||||
ui_status_end(op, ret == 0 ? "done" : "failed");
|
||||
}
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
ui_log(op, "Failed to run `%s`:\n\n%s", cmd, *cmd_data);
|
||||
}
|
||||
nvfree(cmd);
|
||||
|
||||
done:
|
||||
nvfree(tool_path);
|
||||
nvfree(kernel_args);
|
||||
nvfree(path_args);
|
||||
|
||||
if (!data) {
|
||||
nvfree(buf);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* run_initramfs_tool() - attempt to run the specified tool with the minimum
|
||||
* required command line arguments, falling back to more explicitly specified
|
||||
* command line arguments upon failure. */
|
||||
static int run_initramfs_tool(Options *op, int tool, char **data,
|
||||
int interactive)
|
||||
{
|
||||
int ret = -1;
|
||||
/* Always specify the kernel version if the tool requires it, or if the
|
||||
* installer has an explicit kernel version set, which typically indicates
|
||||
* that a kernel other than the currently running one is being targeted. */
|
||||
int kernel_required = initramfs_tools[tool].requires_kernel ||
|
||||
op->kernel_name != NULL;
|
||||
|
||||
if (data) {
|
||||
*data = NULL;
|
||||
}
|
||||
|
||||
/* Run without specifying kernel or initramfs path, if neither is required. */
|
||||
if (!kernel_required && !initramfs_tools[tool].requires_path) {
|
||||
ret = initramfs_tool_helper(op, tool, NULL, NULL, data, interactive);
|
||||
}
|
||||
|
||||
/* Run with only the initramfs path, if a kernel is not required. */
|
||||
if (ret != 0 && !kernel_required) {
|
||||
if (data) {
|
||||
nvfree(*data);
|
||||
}
|
||||
ret = initramfs_tool_helper(op, tool, NULL, get_initramfs_path(op),
|
||||
data, interactive);
|
||||
}
|
||||
|
||||
/* Run with only the kernel, if an initramfs path is not required. */
|
||||
if (ret != 0 && !initramfs_tools[tool].requires_path) {
|
||||
if (data) {
|
||||
nvfree(*data);
|
||||
}
|
||||
ret = initramfs_tool_helper(op, tool, get_kernel_name(op), NULL, data,
|
||||
interactive);
|
||||
}
|
||||
|
||||
/* Run with both the kernel and initramfs path. */
|
||||
if (ret != 0) {
|
||||
if (data) {
|
||||
nvfree(*data);
|
||||
}
|
||||
ret = initramfs_tool_helper(op, tool, get_kernel_name(op),
|
||||
get_initramfs_path(op), data, interactive);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static pthread_t scan_thread;
|
||||
|
||||
typedef struct {
|
||||
int tool;
|
||||
int nouveau_ko_detected;
|
||||
int nvidia_ko_detected;
|
||||
int scan_attempted;
|
||||
int scan_succeeded;
|
||||
} ScanThreadData;
|
||||
|
||||
static void scan_initramfs(Options *op, ScanThreadData *data, int interactive)
|
||||
{
|
||||
if (data->tool < 0) {
|
||||
ui_log(op, "Unable to scan initramfs: no tool found");
|
||||
} else {
|
||||
char *listing;
|
||||
int ret;
|
||||
|
||||
ui_log(op, "Scanning the initramfs with %s...",
|
||||
initramfs_tools[data->tool].name);
|
||||
|
||||
ret = run_initramfs_tool(op, data->tool, &listing, interactive);
|
||||
data->scan_attempted = TRUE;
|
||||
data->scan_succeeded = FALSE;
|
||||
|
||||
if (ret == 0) {
|
||||
int i;
|
||||
|
||||
if (strstr(listing, "/nouveau.ko")) {
|
||||
ui_log(op, "Nouveau detected in initramfs");
|
||||
|
||||
data->nouveau_ko_detected = TRUE;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_conflicting_kernel_modules; i++) {
|
||||
char *module = nvstrcat("/", conflicting_kernel_modules[i],
|
||||
".ko", NULL);
|
||||
if (strstr(listing, module)) {
|
||||
ui_log(op, "%s detected in initramfs", module + 1);
|
||||
|
||||
data->nvidia_ko_detected = TRUE;
|
||||
}
|
||||
|
||||
nvfree(module);
|
||||
|
||||
if (data->nvidia_ko_detected) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
data->scan_succeeded = TRUE;
|
||||
}
|
||||
nvfree(listing);
|
||||
|
||||
ui_log(op, "Initramfs scan %s.", ret == 0 ? "complete" : "failed");
|
||||
}
|
||||
}
|
||||
|
||||
static void *initramfs_scan_worker(void *arg)
|
||||
{
|
||||
static ScanThreadData data;
|
||||
Options *op = arg;
|
||||
|
||||
data.tool = find_initramfs_tool(op, INITRAMFS_LIST_TOOL, NON_INTERACTIVE);
|
||||
|
||||
scan_initramfs(op, &data, NON_INTERACTIVE);
|
||||
|
||||
return &data;
|
||||
}
|
||||
|
||||
int begin_initramfs_scan(Options *op)
|
||||
{
|
||||
static int scan_started;
|
||||
int ret;
|
||||
|
||||
if (scan_started) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ret = pthread_create(&scan_thread, NULL, initramfs_scan_worker, op);
|
||||
|
||||
if (ret == 0) {
|
||||
scan_started = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Attempt to detect conditions under which an initramfs rebuild may be useful,
|
||||
* and guide user through rebuilding if desired. Returns TRUE on success, or if
|
||||
* not rebuilding. Returns FALSE if a rebuild was attempted, but failed. */
|
||||
int update_initramfs(Options *op)
|
||||
{
|
||||
int rebuild_tool, ret = FALSE, pthread_join_ret;
|
||||
const char *no_listing = "Unable to determine whether NVIDIA kernel "
|
||||
"modules are present in the initramfs. Existing "
|
||||
"NVIDIA kernel modules in the initramfs, if any, "
|
||||
"may interfere with the newly installed driver.";
|
||||
const char * const choices[] = {
|
||||
"Do not rebuild initramfs",
|
||||
"Rebuild initramfs"
|
||||
};
|
||||
ScanThreadData data = {}, *data_pointer;
|
||||
char *reason;
|
||||
|
||||
rebuild_tool = find_initramfs_tool(op, INITRAMFS_REBUILD_TOOL, INTERACTIVE);
|
||||
|
||||
/* Handle explicit user requests for initramfs rebuilding behavior */
|
||||
if (op->rebuild_initramfs != NV_OPTIONAL_BOOL_DEFAULT) {
|
||||
if (op->rebuild_initramfs == NV_OPTIONAL_BOOL_TRUE) {
|
||||
if (rebuild_tool >= 0) {
|
||||
ret = run_initramfs_tool(op, rebuild_tool, NULL, INTERACTIVE)
|
||||
== 0;
|
||||
} else {
|
||||
ui_warn(op, "An initramfs rebuild was requested on the "
|
||||
"installer command line, but a suitable tool was "
|
||||
"not found.");
|
||||
}
|
||||
} else {
|
||||
ret = TRUE;
|
||||
ui_log(op, "Skipping initramfs rebuild.");
|
||||
}
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
pthread_join_ret = pthread_join(scan_thread, (void **) &data_pointer);
|
||||
|
||||
if (pthread_join_ret != 0) {
|
||||
data_pointer = &data;
|
||||
}
|
||||
|
||||
if (!data_pointer->scan_attempted) {
|
||||
data_pointer->tool = find_initramfs_tool(op, INITRAMFS_LIST_TOOL,
|
||||
INTERACTIVE);
|
||||
|
||||
scan_initramfs(op, data_pointer, INTERACTIVE);
|
||||
}
|
||||
|
||||
reason = nvstrdup("");
|
||||
|
||||
if (nouveau_is_present()) {
|
||||
add_bullet_list_item("nvidia-installer attempted to disable Nouveau.",
|
||||
&reason);
|
||||
}
|
||||
|
||||
if (data_pointer->nouveau_ko_detected) {
|
||||
add_bullet_list_item("Nouveau is present in the initramfs.", &reason);
|
||||
}
|
||||
|
||||
if (data_pointer->nvidia_ko_detected) {
|
||||
add_bullet_list_item("An NVIDIA kernel module was found in the "
|
||||
"initramfs.", &reason);
|
||||
}
|
||||
|
||||
/* If rebuilding tools were detected, ask user whether to rebuild. */
|
||||
if (rebuild_tool >= 0) {
|
||||
int rebuild = FALSE;
|
||||
|
||||
if (reason[0]) {
|
||||
rebuild = ui_multiple_choice(op, choices, 2, 1,
|
||||
"The initramfs will likely need to be "
|
||||
"rebuilt due to the following "
|
||||
"condition(s):\n%s\n"
|
||||
"Would you like to rebuild the "
|
||||
"initramfs?", reason);
|
||||
} else if (data_pointer->tool < 0 || !data_pointer->scan_succeeded) {
|
||||
rebuild = ui_multiple_choice(op, choices, 2, 0,
|
||||
"%s Would you like to rebuild "
|
||||
"the initramfs?", no_listing);
|
||||
} else {
|
||||
ui_log(op, "No NVIDIA modules detected in the initramfs.");
|
||||
ret = TRUE;
|
||||
}
|
||||
|
||||
if (rebuild) {
|
||||
ret = run_initramfs_tool(op, rebuild_tool, NULL, INTERACTIVE) == 0;
|
||||
|
||||
if (!ret) {
|
||||
ui_error(op, "Failed to rebuild the initramfs!");
|
||||
}
|
||||
} else {
|
||||
ui_log(op, "The initramfs will not be rebuild.");
|
||||
ret = TRUE;
|
||||
}
|
||||
} else if (reason[0]) {
|
||||
/* Alert user that an initramfs rebuild may be needed, but tools to do so
|
||||
* were not detected. */
|
||||
ui_warn(op, "nvidia-installer was unable to locate a tool for "
|
||||
"rebuilding the initramfs, which is strongly recommended "
|
||||
"due to the following condition(s):\n%s\n"
|
||||
"Please consult your distribution's documentation for "
|
||||
"instructions on how to rebuild the initramfs.", reason);
|
||||
ret = TRUE;
|
||||
} else if (data_pointer->tool < 0 || !data_pointer->scan_succeeded) {
|
||||
ui_message(op, "%s", no_listing);
|
||||
ret = TRUE;
|
||||
}
|
||||
|
||||
nvfree(reason);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
25
initramfs.h
Normal file
25
initramfs.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2023 NVIDIA Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
#ifndef __INITRAMFS_H__
|
||||
#define __INITRAMFS_H__
|
||||
|
||||
#include <nvidia-installer.h>
|
||||
|
||||
int begin_initramfs_scan(Options *op);
|
||||
int update_initramfs(Options *op);
|
||||
|
||||
#endif
|
@@ -190,6 +190,27 @@ int install_from_cwd(Options *op)
|
||||
ran_pre_install_hook = TRUE;
|
||||
}
|
||||
|
||||
if (!op->no_kernel_modules) {
|
||||
PrecompiledInfo *info = find_precompiled_kernel_interface(op, p);
|
||||
|
||||
if (info) {
|
||||
free_precompiled(info);
|
||||
|
||||
/*
|
||||
* make sure the required development tools are present on
|
||||
* this system before trying to link the kernel interface.
|
||||
*/
|
||||
if (!check_precompiled_kernel_interface_tools(op)) return FALSE;
|
||||
} else {
|
||||
/*
|
||||
* make sure the required development tools are present on
|
||||
* this system before attempting to verify the compiler and
|
||||
* trying to build a custom kernel interface.
|
||||
*/
|
||||
if (!check_development_tools(op, p)) return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* fail if the nouveau driver is currently in use */
|
||||
|
||||
if (!check_for_nouveau(op)) goto failed;
|
||||
@@ -476,15 +497,6 @@ static int install_kernel_modules(Options *op, Package *p)
|
||||
|
||||
int i, precompiled_success = TRUE;
|
||||
|
||||
/*
|
||||
* make sure the required development tools are present on
|
||||
* this system before trying to link the kernel interface.
|
||||
*/
|
||||
if (!check_precompiled_kernel_interface_tools(op)) {
|
||||
precompiled_success = FALSE;
|
||||
goto precompiled_done;
|
||||
}
|
||||
|
||||
/*
|
||||
* we have a prebuilt kernel interface package, so now link the
|
||||
* kernel interface files to produce the kernel module.
|
||||
@@ -499,22 +511,15 @@ static int install_kernel_modules(Options *op, Package *p)
|
||||
if (!unpack_kernel_modules(op, p, p->kernel_module_build_directory,
|
||||
&(precompiled_info->files[i]))) {
|
||||
precompiled_success = FALSE;
|
||||
goto precompiled_done;
|
||||
break;
|
||||
}
|
||||
}
|
||||
precompiled_done:
|
||||
|
||||
free_precompiled(precompiled_info);
|
||||
if (!precompiled_success) {
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* make sure the required development tools are present on
|
||||
* this system before attempting to verify the compiler and
|
||||
* trying to build a custom kernel interface.
|
||||
*/
|
||||
if (!check_development_tools(op, p)) return FALSE;
|
||||
|
||||
/*
|
||||
* we do not have a prebuilt kernel interface; thus we'll need
|
||||
* to compile the kernel interface, so determine where the
|
||||
@@ -781,19 +786,17 @@ static Package *parse_manifest (Options *op)
|
||||
p->excluded_kernel_modules = nvstrdup("");
|
||||
|
||||
/*
|
||||
* ignore the fifth and sixth lines
|
||||
* ignore the fifth through eigth lines
|
||||
*/
|
||||
|
||||
line++;
|
||||
nvfree(get_next_line(ptr, &ptr, manifest, len));
|
||||
line++;
|
||||
nvfree(get_next_line(ptr, &ptr, manifest, len));
|
||||
|
||||
/* the seventh line is the kernel module build directory */
|
||||
|
||||
line++;
|
||||
p->kernel_module_build_directory = get_next_line(ptr, &ptr, manifest, len);
|
||||
if (!p->kernel_module_build_directory) goto invalid_manifest_file;
|
||||
nvfree(get_next_line(ptr, &ptr, manifest, len));
|
||||
line++;
|
||||
nvfree(get_next_line(ptr, &ptr, manifest, len));
|
||||
|
||||
/*
|
||||
* allow the kernel module build directory to be overridden from the command
|
||||
@@ -801,25 +804,14 @@ static Package *parse_manifest (Options *op)
|
||||
*/
|
||||
|
||||
if (op->kernel_module_build_directory_override) {
|
||||
nvfree(p->kernel_module_build_directory);
|
||||
p->kernel_module_build_directory =
|
||||
nvstrdup(op->kernel_module_build_directory_override);
|
||||
} else {
|
||||
p->kernel_module_build_directory = nvstrdup("kernel");
|
||||
}
|
||||
|
||||
remove_trailing_slashes(p->kernel_module_build_directory);
|
||||
|
||||
/*
|
||||
* the eighth line is the directory containing precompiled kernel
|
||||
* interfaces
|
||||
*/
|
||||
|
||||
line++;
|
||||
p->precompiled_kernel_interface_directory =
|
||||
get_next_line(ptr, &ptr, manifest, len);
|
||||
if (!p->precompiled_kernel_interface_directory)
|
||||
goto invalid_manifest_file;
|
||||
remove_trailing_slashes(p->precompiled_kernel_interface_directory);
|
||||
|
||||
/* the rest of the file is file entries */
|
||||
|
||||
line++;
|
||||
@@ -1095,8 +1087,6 @@ static void free_package(Package *p)
|
||||
|
||||
nvfree(p->kernel_module_build_directory);
|
||||
|
||||
nvfree(p->precompiled_kernel_interface_directory);
|
||||
|
||||
for (i = 0; i < p->num_kernel_modules; i++) {
|
||||
free_kernel_module_info(p->kernel_modules[i]);
|
||||
}
|
||||
@@ -1221,7 +1211,7 @@ static int assisted_module_signing(Options *op, Package *p)
|
||||
"one?") == 1);
|
||||
|
||||
if (generate_keys) {
|
||||
char *cmdline, *x509_hash, *private_key_path, *public_key_path;
|
||||
char *x509_hash, *private_key_path, *public_key_path;
|
||||
int ret, generate_failed = FALSE;
|
||||
const RunCommandOutputMatch output_match[] = {
|
||||
{ .lines = 8, .initial_match = NULL },
|
||||
@@ -1309,19 +1299,16 @@ guess_fail:
|
||||
* in DER format; if this changes in the future we will need
|
||||
* to be able to accommodate the actual required format. */
|
||||
|
||||
cmdline = nvstrcat("cd ", p->kernel_module_build_directory, "; ",
|
||||
op->utils[OPENSSL], " req -new -x509 -newkey "
|
||||
"rsa:2048 -days 7300 -nodes -subj "
|
||||
"\"/CN=nvidia-installer generated signing key/\""
|
||||
" -keyout ", private_key_path,
|
||||
" -outform DER -out ", public_key_path,
|
||||
" -", x509_hash, NULL);
|
||||
ret = run_command(op, NULL, TRUE, output_match, TRUE,
|
||||
"cd ", p->kernel_module_build_directory, "; ",
|
||||
op->utils[OPENSSL], " req -new -x509 -newkey "
|
||||
"rsa:2048 -days 7300 -nodes -subj "
|
||||
"\"/CN=nvidia-installer generated signing key/\""
|
||||
" -keyout ", private_key_path,
|
||||
" -outform DER -out ", public_key_path,
|
||||
" -", x509_hash, NULL);
|
||||
nvfree(x509_hash);
|
||||
|
||||
ret = run_command(op, cmdline, NULL, TRUE, output_match, TRUE);
|
||||
|
||||
nvfree(cmdline);
|
||||
|
||||
if (ret != 0) {
|
||||
ui_error(op, "Failed to generate key pair!");
|
||||
generate_failed = TRUE;
|
||||
@@ -1368,7 +1355,7 @@ generate_done:
|
||||
/* If keys were generated, we should install the verification cert
|
||||
* so that the user can make the kernel trust it, and either delete
|
||||
* or install the private signing key. */
|
||||
char *name, *result = NULL, *fingerprint, *cmdline;
|
||||
char *name, *result = NULL, *fingerprint;
|
||||
char short_fingerprint[9];
|
||||
int ret, delete_secret_key;
|
||||
|
||||
@@ -1380,11 +1367,10 @@ generate_done:
|
||||
/* Get the fingerprint of the X.509 certificate. We already used
|
||||
openssl to create a key pair at this point, so we know we have it;
|
||||
otherwise, we would have already returned by now. */
|
||||
cmdline = nvstrcat(op->utils[OPENSSL], " x509 -noout -fingerprint ",
|
||||
"-inform DER -in ", op->module_signing_public_key,
|
||||
NULL);
|
||||
ret = run_command(op, cmdline, &result, FALSE, NULL, FALSE);
|
||||
nvfree(cmdline);
|
||||
ret = run_command(op, &result, FALSE, NULL, FALSE,
|
||||
op->utils[OPENSSL], " x509 -noout -fingerprint ",
|
||||
"-inform DER -in ", op->module_signing_public_key,
|
||||
NULL);
|
||||
|
||||
/* Format: "SHA1 Fingerprint=00:00:00:00:..." */
|
||||
fingerprint = strchr(result, '=') + 1;
|
||||
@@ -1395,11 +1381,10 @@ generate_done:
|
||||
if (sha1sum) {
|
||||
/* the openssl command failed, or we parsed its output
|
||||
* 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, NULL, FALSE);
|
||||
ret = run_command(op, &result, FALSE, NULL, FALSE,
|
||||
sha1sum, " ", op->module_signing_public_key,
|
||||
NULL);
|
||||
nvfree(sha1sum);
|
||||
nvfree(cmdline);
|
||||
|
||||
fingerprint = result;
|
||||
}
|
||||
|
180
kernel.c
180
kernel.c
@@ -155,7 +155,7 @@ int determine_kernel_module_installation_path(Options *op)
|
||||
static int run_conftest(Options *op, const char *dir, const char *args,
|
||||
char **result)
|
||||
{
|
||||
char *cmd, *kernel_source_path, *kernel_output_path;
|
||||
char *kernel_source_path, *kernel_output_path;
|
||||
const char *arch;
|
||||
int ret;
|
||||
|
||||
@@ -180,15 +180,14 @@ static int run_conftest(Options *op, const char *dir, const char *args,
|
||||
kernel_output_path = op->kernel_output_path;
|
||||
}
|
||||
|
||||
cmd = nvstrcat("sh \"", dir, "/conftest.sh\" \"",
|
||||
op->utils[CC], "\" \"",
|
||||
arch, "\" \"",
|
||||
kernel_source_path, "\" \"",
|
||||
kernel_output_path, "\" ",
|
||||
args, NULL);
|
||||
|
||||
ret = run_command(op, cmd, result, FALSE, 0, TRUE);
|
||||
nvfree(cmd);
|
||||
ret = run_command(op, result, FALSE, 0, TRUE,
|
||||
"sh \"", dir, "/conftest.sh\" \"",
|
||||
op->utils[CC], "\" \"",
|
||||
arch, "\" \"",
|
||||
kernel_source_path, "\" \"",
|
||||
kernel_output_path, "\" ",
|
||||
args, NULL);
|
||||
|
||||
return ret == 0;
|
||||
} /* run_conftest() */
|
||||
@@ -493,7 +492,6 @@ static int attach_signature(Options *op, Package *p,
|
||||
int unpack_kernel_modules(Options *op, Package *p, const char *build_directory,
|
||||
const PrecompiledFileInfo *fileInfo)
|
||||
{
|
||||
char *cmd;
|
||||
int ret;
|
||||
uint32 attrmask;
|
||||
|
||||
@@ -513,16 +511,13 @@ int unpack_kernel_modules(Options *op, Package *p, const char *build_directory,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cmd = nvstrcat("cd ", build_directory,
|
||||
"; ", op->utils[LD], " ", LD_OPTIONS, " -o ",
|
||||
fileInfo->linked_module_name, " ",
|
||||
fileInfo->target_directory, "/", fileInfo->name, " ",
|
||||
fileInfo->target_directory, "/", fileInfo->core_object_name,
|
||||
NULL);
|
||||
|
||||
ret = run_command(op, cmd, NULL, TRUE, 0, TRUE);
|
||||
|
||||
free(cmd);
|
||||
ret = run_command(op, NULL, TRUE, 0, TRUE,
|
||||
"cd ", build_directory,
|
||||
"; ", op->utils[LD], " ", LD_OPTIONS, " -o ",
|
||||
fileInfo->linked_module_name, " ",
|
||||
fileInfo->target_directory, "/", fileInfo->name, " ",
|
||||
fileInfo->target_directory, "/", fileInfo->core_object_name,
|
||||
NULL);
|
||||
|
||||
if (ret != 0) {
|
||||
ui_error(op, "Unable to link kernel module.");
|
||||
@@ -554,20 +549,20 @@ static RunCommandOutputMatch *count_lines(Options *op, Package *p,
|
||||
{
|
||||
RunCommandOutputMatch *ret = nvalloc(sizeof(*ret) * 5);
|
||||
int conftest_count, object_count, module_count, count_success = FALSE;
|
||||
char *data = NULL, *cmd;
|
||||
char *data = NULL;
|
||||
|
||||
/*
|
||||
* 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 (run_command(op, &data, FALSE, NULL, TRUE,
|
||||
"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) == 0) {
|
||||
if (sscanf(data, "conftests:%d objects:%d modules:%d",
|
||||
&conftest_count, &object_count, &module_count) == 3) {
|
||||
count_success = TRUE;
|
||||
@@ -702,7 +697,6 @@ int sign_kernel_module(Options *op, const char *build_directory,
|
||||
{ 0 }
|
||||
};
|
||||
int success;
|
||||
char *cmd;
|
||||
|
||||
/* Lazily set the default value for module_signing_script. */
|
||||
|
||||
@@ -740,13 +734,12 @@ int sign_kernel_module(Options *op, const char *build_directory,
|
||||
"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);
|
||||
success = (run_command(op, NULL, TRUE, output_match, TRUE,
|
||||
"\"", op->module_signing_script, "\" ",
|
||||
op->module_signing_hash, " \"",
|
||||
op->module_signing_secret_key, "\" \"",
|
||||
op->module_signing_public_key, "\" \"",
|
||||
build_directory, "/", module_filename, "\"", NULL) == 0);
|
||||
|
||||
if (status) {
|
||||
ui_status_end(op, success ? "done." : "Failed to sign kernel module.");
|
||||
@@ -1357,16 +1350,14 @@ static void toggle_udev_event_queue(Options *op, int enable)
|
||||
* so udevadm(8) can return right away.
|
||||
*/
|
||||
const char *timeout = enable ? " --timeout=0" : NULL;
|
||||
char *cmd, *data;
|
||||
char *data;
|
||||
int cmd_ret;
|
||||
|
||||
cmd = nvstrcat(udevadm, " control --", verb, "-exec-queue", timeout,
|
||||
NULL);
|
||||
cmd_ret = run_command(op, &data, FALSE, NULL, TRUE,
|
||||
udevadm, " control --", verb, "-exec-queue", timeout,
|
||||
NULL);
|
||||
nvfree(udevadm);
|
||||
|
||||
cmd_ret = run_command(op, cmd, &data, FALSE, NULL, TRUE) != 0;
|
||||
nvfree(cmd);
|
||||
|
||||
if (cmd_ret != 0) {
|
||||
ui_warn(op, "Failed to %s the udev event queue:\n\n%s",
|
||||
verb, data);
|
||||
@@ -1386,15 +1377,13 @@ static void toggle_udev_event_queue(Options *op, int enable)
|
||||
*/
|
||||
static void log_dmesg(Options *op)
|
||||
{
|
||||
char *cmd = NULL, *data = NULL;
|
||||
char *data = NULL;
|
||||
|
||||
cmd = nvstrcat(op->utils[DMESG], " | ",
|
||||
op->utils[TAIL], " -n 25", NULL);
|
||||
|
||||
if (!run_command(op, cmd, &data, FALSE, NULL, TRUE))
|
||||
if (!run_command(op, &data, FALSE, NULL, TRUE,
|
||||
op->utils[DMESG], " | ", op->utils[TAIL], " -n 25", NULL)) {
|
||||
ui_log(op, "Kernel messages:\n%s", data);
|
||||
}
|
||||
|
||||
nvfree(cmd);
|
||||
nvfree(data);
|
||||
}
|
||||
|
||||
@@ -1585,28 +1574,25 @@ static int modprobe_helper(Options *op, const char *module_name,
|
||||
int quiet, int unload)
|
||||
{
|
||||
int ret = 0, old_loglevel, loglevel_set;
|
||||
char *cmd, *data;
|
||||
char *data;
|
||||
|
||||
if (op->skip_module_load) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cmd = nvstrcat(op->utils[MODPROBE],
|
||||
quiet ? " -q" : "",
|
||||
unload ? " -r" : "",
|
||||
" ", module_name,
|
||||
NULL);
|
||||
|
||||
loglevel_set = set_loglevel(PRINTK_LOGLEVEL_KERN_ALERT, &old_loglevel);
|
||||
|
||||
ret = run_command(op, cmd, &data, FALSE, NULL, TRUE);
|
||||
ret = run_command(op, &data, FALSE, NULL, TRUE,
|
||||
op->utils[MODPROBE],
|
||||
quiet ? " -q" : "",
|
||||
unload ? " -r" : "",
|
||||
" ", module_name,
|
||||
NULL);
|
||||
|
||||
if (loglevel_set) {
|
||||
set_loglevel(old_loglevel, NULL);
|
||||
}
|
||||
|
||||
nvfree(cmd);
|
||||
|
||||
if (!quiet && ret != 0) {
|
||||
char *expert_detail = nvstrcat(": '", data, "'", NULL);
|
||||
ui_error(op, "Unable to %s the '%s' kernel module%s",
|
||||
@@ -1695,22 +1681,43 @@ int check_for_unloaded_kernel_module(Options *op)
|
||||
/* check again */
|
||||
|
||||
if (check_for_loaded_kernel_module(op, conflicting_kernel_modules[n])) {
|
||||
ui_error(op, "An NVIDIA kernel module '%s' appears to already "
|
||||
"be loaded in your kernel. This may be because it is "
|
||||
"in use (for example, by an X server, a CUDA program, "
|
||||
"or the NVIDIA Persistence Daemon), but this may also "
|
||||
"happen if your kernel was configured without support "
|
||||
"for module unloading. Please be sure to exit any "
|
||||
"programs that may be using the GPU(s) before attempting "
|
||||
"to upgrade your driver. If no GPU-based programs are "
|
||||
"running, you know that your kernel supports module "
|
||||
"unloading, and you still receive this message, then an "
|
||||
"error may have occurred that has corrupted an NVIDIA "
|
||||
"kernel module's usage count, for which the simplest "
|
||||
"remedy is to reboot your computer.",
|
||||
conflicting_kernel_modules[n]);
|
||||
int choice;
|
||||
|
||||
return FALSE;
|
||||
op->loaded_kernel_module_detected = TRUE;
|
||||
|
||||
ui_warn(op, "An NVIDIA kernel module '%s' appears to be already "
|
||||
"loaded in your kernel. This may be because it is in use (for "
|
||||
"example, by an X server, a CUDA program, or the NVIDIA "
|
||||
"Persistence Daemon), but this may also happen if your kernel "
|
||||
"was configured without support for module unloading. Some of "
|
||||
"the sanity checks that nvidia-installer performs to detect "
|
||||
"potential installation problems are not possible while an "
|
||||
"NVIDIA kernel module is running.",
|
||||
conflicting_kernel_modules[n]);
|
||||
|
||||
choice = ui_multiple_choice(op, CONTINUE_ABORT_CHOICES,
|
||||
NUM_CONTINUE_ABORT_CHOICES,
|
||||
op->allow_installation_with_running_driver ?
|
||||
CONTINUE_CHOICE : ABORT_CHOICE,
|
||||
"Would you like to continue installation and skip the sanity "
|
||||
"checks? If not, please abort the installation, then close "
|
||||
"any programs which may be using the NVIDIA GPU(s), and "
|
||||
"attempt installation again.");
|
||||
|
||||
if (choice == CONTINUE_CHOICE) {
|
||||
ui_warn(op, "Continuing installation despite the presence of a "
|
||||
"loaded NVIDIA kernel module. Some sanity checks will not "
|
||||
"be performed. It is strongly recommended that you reboot "
|
||||
"your computer after installation is complete. If the "
|
||||
"installation is not successful after rebooting the "
|
||||
"computer, you can run `nvidia-uninstall` to attempt to "
|
||||
"remove the NVIDIA driver.");
|
||||
|
||||
op->skip_module_load = TRUE;
|
||||
ui_log(op, "Kernel module load tests will be skipped.");
|
||||
}
|
||||
|
||||
return choice == CONTINUE_CHOICE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1719,6 +1726,12 @@ int check_for_unloaded_kernel_module(Options *op)
|
||||
}
|
||||
|
||||
|
||||
char *precompiled_kernel_interface_path(const Package *p)
|
||||
{
|
||||
return nvdircat(p->kernel_module_build_directory, "precompiled", NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* find_precompiled_kernel_interface() - do assorted black magic to
|
||||
* determine if the given package contains a precompiled kernel interface
|
||||
@@ -1794,8 +1807,9 @@ PrecompiledInfo *find_precompiled_kernel_interface(Options *op, Package *p)
|
||||
*/
|
||||
|
||||
if (!info) {
|
||||
info = scan_dir(op, p, p->precompiled_kernel_interface_directory,
|
||||
proc_version_string, search_filelist);
|
||||
char *dir = precompiled_kernel_interface_path(p);
|
||||
info = scan_dir(op, p, dir, proc_version_string, search_filelist);
|
||||
nvfree(dir);
|
||||
}
|
||||
|
||||
/* If we found one, ask expert users if they really want to use it */
|
||||
@@ -2159,8 +2173,8 @@ 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, NULL, TRUE);
|
||||
|
||||
ret = run_command(op, &result, FALSE, NULL, TRUE, op->utils[LSMOD], NULL);
|
||||
|
||||
if ((ret == 0) && (result) && (result[0] != '\0')) {
|
||||
char *ptr;
|
||||
int len = strlen(module_name);
|
||||
@@ -2189,20 +2203,16 @@ static int check_for_loaded_kernel_module(Options *op, const char *module_name)
|
||||
int rmmod_kernel_module(Options *op, const char *module_name)
|
||||
{
|
||||
int ret, old_loglevel, loglevel_set;
|
||||
char *cmd;
|
||||
|
||||
cmd = nvstrcat(op->utils[RMMOD], " ", module_name, NULL);
|
||||
|
||||
loglevel_set = set_loglevel(PRINTK_LOGLEVEL_KERN_ALERT, &old_loglevel);
|
||||
|
||||
ret = run_command(op, cmd, NULL, FALSE, NULL, TRUE);
|
||||
|
||||
ret = run_command(op, NULL, FALSE, NULL, TRUE,
|
||||
op->utils[RMMOD], " ", module_name, NULL);
|
||||
|
||||
if (loglevel_set) {
|
||||
set_loglevel(old_loglevel, NULL);
|
||||
}
|
||||
|
||||
free(cmd);
|
||||
|
||||
return ret ? FALSE : TRUE;
|
||||
|
||||
} /* rmmod_kernel_module() */
|
||||
@@ -2405,7 +2415,7 @@ static int run_make(Options *op, Package *p, const char *dir,
|
||||
ui_status_begin(op, status, "");
|
||||
}
|
||||
|
||||
ret = (run_command(op, cmd, &data, TRUE, status ? match : NULL, TRUE) == 0);
|
||||
ret = (run_command(op, &data, TRUE, status ? match : NULL, TRUE, cmd, NULL) == 0);
|
||||
|
||||
if (status) {
|
||||
if (ret) {
|
||||
|
1
kernel.h
1
kernel.h
@@ -56,6 +56,7 @@ int package_includes_kernel_module (const Package*,
|
||||
int rmmod_kernel_module (Options*, const char *);
|
||||
int conftest_sanity_check (Options*, const char *,
|
||||
const char *, const char *);
|
||||
char *precompiled_kernel_interface_path (const Package*);
|
||||
|
||||
#ifndef ENOKEY
|
||||
#define ENOKEY 126 /* Required key not available */
|
||||
|
361
misc.c
361
misc.c
@@ -48,6 +48,8 @@
|
||||
#include "nvLegacy.h"
|
||||
#include "manifest.h"
|
||||
#include "nvpci-utils.h"
|
||||
#include "conflicting-kernel-modules.h"
|
||||
#include "initramfs.h"
|
||||
#include "detect-self-hosted.h"
|
||||
|
||||
static int check_symlink(Options*, const char*, const char*, const char*);
|
||||
@@ -247,16 +249,29 @@ char *get_next_line(char *buf, char **end, char *start, int length)
|
||||
* command to run?
|
||||
*/
|
||||
|
||||
int run_command(Options *op, const char *cmd, char **data, int output,
|
||||
const RunCommandOutputMatch *output_match, int redirect)
|
||||
int run_command(Options *op, char **data, int output,
|
||||
const RunCommandOutputMatch *output_match, int redirect,
|
||||
const char *cmd_start, ...)
|
||||
{
|
||||
int n, len, buflen, ret, total_lines;
|
||||
char *cmd2, *buf, *tmpbuf;
|
||||
int n = 0; /* output line counter */
|
||||
int len = 0; /* length of what has actually been read */
|
||||
int buflen = 0; /* length of destination buffer */
|
||||
int ret, total_lines;
|
||||
char *cmd, *buf = NULL;
|
||||
FILE *stream = NULL;
|
||||
struct sigaction act, old_act;
|
||||
float percent;
|
||||
int *match_sizes = NULL;
|
||||
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, cmd_start);
|
||||
cmd = nvvstrcat(cmd_start, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (!cmd) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (data) *data = NULL;
|
||||
|
||||
/*
|
||||
@@ -269,9 +284,9 @@ int run_command(Options *op, const char *cmd, char **data, int output,
|
||||
/* redirect stderr to stdout */
|
||||
|
||||
if (redirect) {
|
||||
cmd2 = nvstrcat(cmd, " 2>&1", NULL);
|
||||
} else {
|
||||
cmd2 = nvstrdup(cmd);
|
||||
char *tmp = cmd;
|
||||
cmd = nvstrcat(cmd, " 2>&1", NULL);
|
||||
nvfree(tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -304,24 +319,24 @@ int run_command(Options *op, const char *cmd, char **data, int output,
|
||||
* command.
|
||||
*/
|
||||
|
||||
stream = popen(cmd2, "r");
|
||||
nvfree(cmd2);
|
||||
stream = popen(cmd, "r");
|
||||
|
||||
if (stream == NULL) {
|
||||
ret = errno;
|
||||
ui_error(op, "Failure executing command '%s' (%s).",
|
||||
cmd, strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
|
||||
nvfree(cmd);
|
||||
|
||||
if (stream == NULL) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* read from the stream, filling and growing buf, until we hit
|
||||
* EOF. Send each line to the ui as it is read.
|
||||
*/
|
||||
|
||||
len = 0; /* length of what has actually been read */
|
||||
buflen = 0; /* length of destination buffer */
|
||||
buf = NULL;
|
||||
n = 0; /* output line counter */
|
||||
|
||||
if (output_match) {
|
||||
int match_count, i;
|
||||
@@ -356,12 +371,7 @@ int run_command(Options *op, const char *cmd, char **data, int output,
|
||||
|
||||
if ((buflen - len) < NV_MIN_LINE_LEN) {
|
||||
buflen += NV_LINE_LEN;
|
||||
tmpbuf = (char *) nvalloc(buflen);
|
||||
if (buf) {
|
||||
memcpy(tmpbuf, buf, len);
|
||||
free(buf);
|
||||
}
|
||||
buf = tmpbuf;
|
||||
buf = nvrealloc(buf, buflen);
|
||||
}
|
||||
|
||||
if (fgets(buf + len, buflen - len, stream) == NULL) break;
|
||||
@@ -386,8 +396,16 @@ int run_command(Options *op, const char *cmd, char **data, int output,
|
||||
* XXX: manually call the SIGWINCH handler, if set, to
|
||||
* handle window resizes while we ignore the signal.
|
||||
*/
|
||||
if (op->sigwinch_workaround)
|
||||
if (old_act.sa_handler) old_act.sa_handler(SIGWINCH);
|
||||
if (op->sigwinch_workaround) {
|
||||
/* Only call into the handler if it isn't one of the special
|
||||
* pointer values from bits/signum-generic.h */
|
||||
if (old_act.sa_handler != NULL &&
|
||||
old_act.sa_handler != SIG_DFL &&
|
||||
old_act.sa_handler != SIG_IGN &&
|
||||
old_act.sa_handler != SIG_ERR) {
|
||||
old_act.sa_handler(SIGWINCH);
|
||||
}
|
||||
}
|
||||
|
||||
ui_status_update(op, percent, NULL);
|
||||
}
|
||||
@@ -1323,11 +1341,8 @@ static int unprelink(Options *op, const char *filename)
|
||||
|
||||
cmd = find_system_util("prelink");
|
||||
if (cmd) {
|
||||
char *cmdline;
|
||||
cmdline = nvstrcat(cmd, " -u ", filename, NULL);
|
||||
ret = run_command(op, cmdline, NULL, FALSE, NULL, TRUE);
|
||||
ret = run_command(op, NULL, FALSE, NULL, TRUE, cmd, " -u ", filename, NULL);
|
||||
nvfree(cmd);
|
||||
nvfree(cmdline);
|
||||
}
|
||||
return ret;
|
||||
} /* unprelink() */
|
||||
@@ -1528,15 +1543,14 @@ static int get_xserver_information(Options *op,
|
||||
|
||||
void query_xorg_version(Options *op)
|
||||
{
|
||||
char *cmd = NULL, *data = NULL;
|
||||
char *data = NULL;
|
||||
int ret = FALSE;
|
||||
|
||||
if (!op->utils[XSERVER])
|
||||
goto done;
|
||||
|
||||
cmd = nvstrcat(op->utils[XSERVER], " -version", NULL);
|
||||
|
||||
if (run_command(op, cmd, &data, FALSE, NULL, TRUE) ||
|
||||
if (run_command(op, &data, FALSE, NULL, TRUE,
|
||||
op->utils[XSERVER], " -version", NULL) ||
|
||||
(data == NULL)) {
|
||||
goto done;
|
||||
}
|
||||
@@ -1565,7 +1579,6 @@ done:
|
||||
}
|
||||
|
||||
nvfree(data);
|
||||
nvfree(cmd);
|
||||
}
|
||||
|
||||
|
||||
@@ -1576,8 +1589,9 @@ done:
|
||||
* /tmp/.X[n]-lock files, where [n] is the number of the X Display
|
||||
* (we'll just check for 0-7). Get the pid contained in this X lock file,
|
||||
* this is the pid of the running X server. If any X server is running,
|
||||
* print an error message and return FALSE. If no X server is running,
|
||||
* return TRUE.
|
||||
* print a warning message and set op->running_x_server_detected. If X is
|
||||
* detected, give the user a choice whether to continue installing (return TRUE)
|
||||
* or abort (return FALSE).
|
||||
*/
|
||||
|
||||
int check_for_running_x(Options *op)
|
||||
@@ -1620,13 +1634,26 @@ int check_for_running_x(Options *op)
|
||||
if (op->no_x_check) {
|
||||
ui_log(op, "Continuing per the '--no-x-check' option.");
|
||||
} else {
|
||||
ui_error(op, "You appear to be running an X server; please "
|
||||
"exit X before installing. For further details, "
|
||||
"please see the section INSTALLING THE NVIDIA "
|
||||
"DRIVER in the README available on the Linux driver "
|
||||
"download page at www.nvidia.com.");
|
||||
return FALSE;
|
||||
int choice = ui_multiple_choice(op, CONTINUE_ABORT_CHOICES,
|
||||
NUM_CONTINUE_ABORT_CHOICES, ABORT_CHOICE,
|
||||
"You appear to be running an X server. Installing the "
|
||||
"NVIDIA driver while X is running is not recommended, "
|
||||
"as doing so may prevent the installer from detecting "
|
||||
"some potential installation problems, and it may not "
|
||||
"be possible to start new graphics applications after "
|
||||
"a new driver is installed. If you choose to continue "
|
||||
"installation, it is highly recommended that you "
|
||||
"reboot your computer after installation to use the "
|
||||
"newly installed driver.");
|
||||
if (choice == CONTINUE_CHOICE) {
|
||||
op->running_x_server_detected = TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* We found a running X server; no need to check for others. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1785,9 +1812,9 @@ int check_selinux(Options *op)
|
||||
case SELINUX_FORCE_NO:
|
||||
if (selinux_available == TRUE) {
|
||||
char *data = NULL;
|
||||
int ret = run_command(op, op->utils[GETENFORCE], &data,
|
||||
FALSE, NULL, TRUE);
|
||||
|
||||
int ret = run_command(op, &data, FALSE, NULL, TRUE,
|
||||
op->utils[GETENFORCE], NULL);
|
||||
|
||||
if ((ret != 0) || (!data)) {
|
||||
ui_warn(op, "Cannot check the current mode of SELinux; "
|
||||
"Command getenforce() failed");
|
||||
@@ -1806,8 +1833,8 @@ int check_selinux(Options *op)
|
||||
case SELINUX_DEFAULT:
|
||||
op->selinux_enabled = FALSE;
|
||||
if (selinux_available == TRUE) {
|
||||
int ret = run_command(op, op->utils[SELINUX_ENABLED], NULL,
|
||||
FALSE, NULL, TRUE);
|
||||
int ret = run_command(op, NULL, FALSE, NULL, TRUE,
|
||||
op->utils[SELINUX_ENABLED], NULL);
|
||||
if (ret == 0) {
|
||||
op->selinux_enabled = TRUE;
|
||||
}
|
||||
@@ -1903,7 +1930,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, NULL, TRUE);
|
||||
cmd_ret = run_command(op, &data, FALSE, NULL, TRUE, cmd, NULL);
|
||||
|
||||
if (cmd_ret != 0) {
|
||||
ui_error(op, "Failed to run `%s`:\n%s", cmd, data);
|
||||
@@ -1965,7 +1992,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, NULL, TRUE);
|
||||
status = run_command(op, NULL, TRUE, NULL, TRUE, cmd, NULL);
|
||||
ui_status_end(op, "done.");
|
||||
|
||||
ret = (status == 0) ? HOOK_SCRIPT_SUCCESS : HOOK_SCRIPT_FAIL;
|
||||
@@ -2097,7 +2124,7 @@ int check_for_alternate_install(Options *op)
|
||||
|
||||
#define SYSFS_DEVICES_PATH "/sys/bus/pci/devices"
|
||||
|
||||
static int nouveau_is_present(void)
|
||||
int nouveau_is_present(void)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent * ent;
|
||||
@@ -2158,22 +2185,22 @@ static const char* modprobe_directories[] = { "/etc/modprobe.d",
|
||||
|
||||
/*
|
||||
* this checksum is the result of compute_crc() for the file contents
|
||||
* written in blacklist_nouveau()
|
||||
* written in disable_nouveau()
|
||||
*/
|
||||
|
||||
#define DISABLE_NOUVEAU_FILE_CKSUM 3728279991U
|
||||
|
||||
/*
|
||||
* blacklist_filename() - generate the filename of a blacklist file. The
|
||||
* caller should ensure that the directory exists, or be able to handle
|
||||
* disable_nouveau_filename() - generate the filename of a configuration file.
|
||||
* The caller should ensure that the directory exists, or be able to handle
|
||||
* failures correctly if the directory does not exist.
|
||||
*/
|
||||
static char *blacklist_filename(const char *directory)
|
||||
static char *disable_nouveau_filename(const char *directory)
|
||||
{
|
||||
return nvstrcat(directory, DISABLE_NOUVEAU_FILE, NULL);
|
||||
}
|
||||
|
||||
static char *write_blacklist_file(const char *directory)
|
||||
static char *write_disable_nouveau_file(const char *directory)
|
||||
{
|
||||
int ret;
|
||||
struct stat stat_buf;
|
||||
@@ -2186,7 +2213,7 @@ static char *write_blacklist_file(const char *directory)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
filename = blacklist_filename(directory);
|
||||
filename = disable_nouveau_filename(directory);
|
||||
file = fopen(filename, "w+");
|
||||
|
||||
if (!file) {
|
||||
@@ -2211,28 +2238,19 @@ static char *write_blacklist_file(const char *directory)
|
||||
|
||||
/*
|
||||
* Write modprobe configuration fragments to disable loading of
|
||||
* nouveau:
|
||||
*
|
||||
* for directory in /etc/modprobe.d /usr/lib/modprobe.d; do
|
||||
* if [ -d $directory ]; then
|
||||
* name=$directory/nvidia-installer-nouveau-blacklist.conf
|
||||
* echo "# generated by nvidia-installer" > $name
|
||||
* echo "blacklist nouveau" >> $name
|
||||
* echo "options nouveau modeset=0" >> $name
|
||||
* fi
|
||||
* done
|
||||
* nouveau.
|
||||
*
|
||||
* Returns a list of written configuration files if successful;
|
||||
* returns NULL if there was a failure.
|
||||
*/
|
||||
|
||||
static char *blacklist_nouveau(void)
|
||||
static char *disable_nouveau(void)
|
||||
{
|
||||
int i;
|
||||
char *filelist = NULL;
|
||||
|
||||
for (i = 0; i < ARRAY_LEN(modprobe_directories); i++) {
|
||||
char *filename = write_blacklist_file(modprobe_directories[i]);
|
||||
char *filename = write_disable_nouveau_file(modprobe_directories[i]);
|
||||
if (filename) {
|
||||
filelist = nv_prepend_to_string_list(filelist, filename, ", ");
|
||||
nvfree(filename);
|
||||
@@ -2245,26 +2263,33 @@ static char *blacklist_nouveau(void)
|
||||
|
||||
|
||||
/*
|
||||
* Check if any nouveau blacklist file is already present with the
|
||||
* Check if any disable nouveau file is already present with the
|
||||
* contents that we expect, and return the paths to any found files,
|
||||
* or NULL if no matching files were found
|
||||
*/
|
||||
|
||||
static char *nouveau_blacklist_file_is_present(Options *op)
|
||||
static char *disable_nouveau_file_is_present(Options *op,
|
||||
int *present_at_all_paths)
|
||||
{
|
||||
int i;
|
||||
int i, directory_count = 0, file_count = 0;
|
||||
char *filelist = NULL;
|
||||
|
||||
for (i = 0; i < ARRAY_LEN(modprobe_directories); i++) {
|
||||
char *filename = blacklist_filename(modprobe_directories[i]);
|
||||
char *filename = disable_nouveau_filename(modprobe_directories[i]);
|
||||
|
||||
if (directory_exists(modprobe_directories[i])) {
|
||||
directory_count++;
|
||||
}
|
||||
|
||||
if ((access(filename, R_OK) == 0) &&
|
||||
(compute_crc(op, filename) == DISABLE_NOUVEAU_FILE_CKSUM)) {
|
||||
file_count++;
|
||||
filelist = nv_prepend_to_string_list(filelist, filename, ", ");
|
||||
}
|
||||
nvfree(filename);
|
||||
}
|
||||
|
||||
*present_at_all_paths = directory_count == file_count;
|
||||
return filelist;
|
||||
}
|
||||
|
||||
@@ -2274,15 +2299,14 @@ static char *nouveau_blacklist_file_is_present(Options *op)
|
||||
* Check if the nouveau kernel driver is in use. If it is, provide an
|
||||
* appropriate error message and offer to try to disable nouveau.
|
||||
*
|
||||
* Returns FALSE if the nouveau kernel driver is in use (cause
|
||||
* installation to abort); returns TRUE if the nouveau driver is not
|
||||
* in use, or if the nouveau check is to be skipped.
|
||||
* Returns FALSE if the user chooses to abort the installation due to
|
||||
* the presence of Nouveau; TRUE otherwise.
|
||||
*/
|
||||
|
||||
int check_for_nouveau(Options *op)
|
||||
{
|
||||
int ret, nouveau_detected;
|
||||
char *blacklist_files;
|
||||
int ret, nouveau_detected, all_files_written;
|
||||
char *disable_files;
|
||||
|
||||
#define NOUVEAU_POINTER_MESSAGE \
|
||||
"Please consult the NVIDIA driver README and your Linux " \
|
||||
@@ -2294,63 +2318,86 @@ int check_for_nouveau(Options *op)
|
||||
nouveau_detected = nouveau_is_present();
|
||||
|
||||
if (nouveau_detected) {
|
||||
ui_error(op, "The Nouveau kernel driver is currently in use "
|
||||
"by your system. This driver is incompatible with the NVIDIA "
|
||||
"driver, and must be disabled before proceeding. "
|
||||
NOUVEAU_POINTER_MESSAGE);
|
||||
} else if (!op->disable_nouveau) {
|
||||
/* If nouveau isn't loaded, we can return early, unless the user
|
||||
* explicitly requested for the blacklist file to be written. */
|
||||
return !nouveau_detected;
|
||||
ui_warn(op, "The Nouveau kernel driver is currently in use "
|
||||
"by your system. This driver is incompatible with the NVIDIA "
|
||||
"driver, and must be disabled before proceeding.");
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
blacklist_files = nouveau_blacklist_file_is_present(op);
|
||||
disable_files = disable_nouveau_file_is_present(op, &all_files_written);
|
||||
|
||||
if (blacklist_files) {
|
||||
if (disable_files) {
|
||||
ui_warn(op, "One or more modprobe configuration files to disable "
|
||||
"Nouveau are already present at: %s. Please be "
|
||||
"sure you have rebooted your system since these files were "
|
||||
"written. If you have rebooted, then Nouveau may be enabled "
|
||||
"for other reasons, such as being included in the system "
|
||||
"initial ramdisk or in your X configuration file. "
|
||||
NOUVEAU_POINTER_MESSAGE, blacklist_files);
|
||||
nvfree(blacklist_files);
|
||||
if (!op->disable_nouveau) {
|
||||
/* If the user explicitly requested that the blacklist files be
|
||||
* written, don't return early, so that the files can be written
|
||||
* again, e.g. in case a file is present, but not in the right
|
||||
* place for this particular system. */
|
||||
return !nouveau_detected;
|
||||
NOUVEAU_POINTER_MESSAGE, disable_files);
|
||||
nvfree(disable_files);
|
||||
if (all_files_written) {
|
||||
/* If all of the possible disable files are already present,
|
||||
* don't offer to write any more. */
|
||||
goto continue_or_abort;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ui_yes_no(op, op->disable_nouveau, "For some distributions, Nouveau "
|
||||
"can be disabled by adding a file in the modprobe "
|
||||
"configuration directory. Would you like nvidia-installer "
|
||||
"to attempt to create this modprobe file for you?");
|
||||
/* Disable files were missing from at least one of the expected locations:
|
||||
* offer to create additional ones. */
|
||||
ret = ui_yes_no(op, op->disable_nouveau,
|
||||
"Nouveau can usually be disabled by adding files "
|
||||
"to the modprobe configuration directories and rebuilding "
|
||||
"the initramfs.\n\n"
|
||||
"Would you like nvidia-installer to attempt to create "
|
||||
"these modprobe configuration files for you?");
|
||||
|
||||
if (ret) {
|
||||
blacklist_files = blacklist_nouveau();
|
||||
disable_files = disable_nouveau();
|
||||
|
||||
if (blacklist_files) {
|
||||
if (disable_files) {
|
||||
ui_message(op, "One or more modprobe configuration files to "
|
||||
"disable Nouveau have been written. "
|
||||
"For some distributions, this may be sufficient to "
|
||||
"disable Nouveau; other distributions may require "
|
||||
"modification of the initial ramdisk. Please reboot "
|
||||
"your system and attempt NVIDIA driver installation "
|
||||
"again. Note if you later wish to re-enable Nouveau, "
|
||||
"you will need to delete these files: %s",
|
||||
blacklist_files);
|
||||
nvfree(blacklist_files);
|
||||
"disable Nouveau have been written. You will need "
|
||||
"to reboot your system and possibly rebuild the initramfs "
|
||||
"before these changes can take effect. Note if you "
|
||||
"later wish to reenable Nouveau, you will need to "
|
||||
"delete these files: %s",
|
||||
disable_files);
|
||||
nvfree(disable_files);
|
||||
} else {
|
||||
ui_warn(op, "Unable to alter the nouveau modprobe configuration. "
|
||||
NOUVEAU_POINTER_MESSAGE);
|
||||
}
|
||||
} else {
|
||||
ui_message(op, "Please disable Nouveau manually and attempt to install "
|
||||
"the NVIDIA driver again later.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Allow installation to continue if nouveau was not detected. */
|
||||
return !nouveau_detected;
|
||||
continue_or_abort:
|
||||
|
||||
ret = ui_multiple_choice(op, CONTINUE_ABORT_CHOICES,
|
||||
NUM_CONTINUE_ABORT_CHOICES,
|
||||
op->allow_installation_with_running_driver ?
|
||||
CONTINUE_CHOICE : ABORT_CHOICE,
|
||||
"nvidia-installer is not able to perform some of the sanity checks "
|
||||
"which detect potential installation problems while Nouveau is loaded. "
|
||||
"Would you like to continue installation without these sanity "
|
||||
"checks, or abort installation, confirm that Nouveau has been "
|
||||
"properly disabled, and attempt installation again later?");
|
||||
|
||||
if (ret == ABORT_CHOICE) {
|
||||
/* Offer to update the initramfs: normally, this happens before
|
||||
* installing files, but the user is explicitly bailing out. */
|
||||
update_initramfs(op);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
op->skip_module_load = TRUE;
|
||||
ui_log(op, "Proceeding with installation despite the presence of Nouveau. "
|
||||
"Kernel module load tests will be skipped.");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define DKMS_STATUS " status"
|
||||
@@ -2413,7 +2460,7 @@ static int run_dkms(Options *op, const char* verb, const char *version,
|
||||
kernopt_all, kernopt, NULL);
|
||||
|
||||
/* Run DKMS */
|
||||
ret = run_command(op, cmdline, &output, FALSE, NULL, TRUE);
|
||||
ret = run_command(op, &output, FALSE, NULL, TRUE, cmdline, NULL);
|
||||
if (ret != 0) {
|
||||
ui_error(op, "Failed to run `%s`: %s", cmdline, output);
|
||||
}
|
||||
@@ -2478,6 +2525,7 @@ static char *dkms_gen_tarball(Options *op, Package *p, const char *kernel)
|
||||
{
|
||||
char *tmpdir, *sourcedir, *treedir, *builddir, *logdir, *moduledir, *dst;
|
||||
char *tarball = NULL;
|
||||
const char *log;
|
||||
int ret, i;
|
||||
|
||||
tmpdir = make_tmpdir(op);
|
||||
@@ -2501,7 +2549,15 @@ static char *dkms_gen_tarball(Options *op, Package *p, const char *kernel)
|
||||
|
||||
/* 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);
|
||||
|
||||
if (p->kernel_make_logs) {
|
||||
log = p->kernel_make_logs;
|
||||
} else {
|
||||
log = "This driver was linked from precompiled interfaces and directly "
|
||||
"registered with DKMS. This process did not preserve build logs.";
|
||||
}
|
||||
|
||||
ret = nv_string_to_file(dst, log);
|
||||
nvfree(dst);
|
||||
if (!ret) goto done;
|
||||
|
||||
@@ -2571,12 +2627,11 @@ static char *dkms_gen_tarball(Options *op, Package *p, const char *kernel)
|
||||
/* 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);
|
||||
ret = run_command(op, &output, FALSE, 0, TRUE,
|
||||
op->utils[TAR], " -C ", tmpdir, " -cf ", tarball,
|
||||
" .", NULL);
|
||||
|
||||
if (ret != 0) {
|
||||
ui_error(op, "Failed to create a DKMS tarball: %s", output);
|
||||
@@ -2640,13 +2695,12 @@ void dkms_register_module(Options *op, Package *p, const char *kernel)
|
||||
/* Create a DKMS tarball */
|
||||
tarball = dkms_gen_tarball(op, p, kernel);
|
||||
if (tarball) {
|
||||
char *cmd, *output;
|
||||
char *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);
|
||||
ret = run_command(op, &output, FALSE, 0, TRUE,
|
||||
op->utils[DKMS], " ldtarball ", tarball, NULL);
|
||||
|
||||
if (ret != 0) {
|
||||
ui_error(op, "Failed to load DKMS tarball: %s", output);
|
||||
@@ -2869,18 +2923,17 @@ char *
|
||||
get_pkg_config_variable(Options *op,
|
||||
const char *pkg, const char *variable)
|
||||
{
|
||||
char *cmd, *prefix = NULL;
|
||||
char *prefix = NULL;
|
||||
int ret;
|
||||
|
||||
if (!op->utils[PKG_CONFIG]) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cmd = nvstrcat(op->utils[PKG_CONFIG],
|
||||
" --variable=", variable, " ", pkg,
|
||||
NULL);
|
||||
ret = run_command(op, cmd, &prefix, FALSE, NULL, TRUE);
|
||||
nvfree(cmd);
|
||||
ret = run_command(op, &prefix, FALSE, NULL, TRUE,
|
||||
op->utils[PKG_CONFIG],
|
||||
" --variable=", variable, " ", pkg,
|
||||
NULL);
|
||||
|
||||
if (ret != 0 ||
|
||||
/*
|
||||
@@ -2962,14 +3015,13 @@ 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);
|
||||
run_command(op, &helptext, FALSE, 0, TRUE,
|
||||
cmd, " ", help, NULL);
|
||||
|
||||
for (match = helptext; match && *match; match = strstr(match + 1, option)) {
|
||||
int before_clear;
|
||||
@@ -3057,3 +3109,52 @@ void check_for_vulkan_loader(Options *op)
|
||||
"\"libvulkan1\" package.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void add_bullet_list_item(const char *new, char **orig)
|
||||
{
|
||||
char *tmp = *orig;
|
||||
|
||||
*orig = nvstrcat(*orig, " * ", new, "\n", NULL);
|
||||
nvfree(tmp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* suggest_reboot() - Give the user a suggestion to reboot the computer if
|
||||
* the conditions during installation call for one.
|
||||
*/
|
||||
|
||||
void suggest_reboot(Options *op)
|
||||
{
|
||||
char *reason = nvstrdup("");
|
||||
|
||||
if (op->loaded_kernel_module_detected) {
|
||||
add_bullet_list_item("Existing NVIDIA kernel modules were loaded "
|
||||
"during installation, and are likely still "
|
||||
"loaded.", &reason);
|
||||
}
|
||||
|
||||
if (op->running_x_server_detected) {
|
||||
add_bullet_list_item("A running X server was detected during "
|
||||
"installation.", &reason);
|
||||
}
|
||||
|
||||
if (nouveau_is_present()) {
|
||||
add_bullet_list_item("Nouveau is running: any attempt to disable it "
|
||||
"will not take effect until after a reboot.",
|
||||
&reason);
|
||||
}
|
||||
|
||||
if (reason[0]) {
|
||||
ui_warn(op, "It is strongly recommended that you reboot your computer "
|
||||
"after exiting the installer, due to the following "
|
||||
"condition(s) which the installer detected: \n\n%s\n"
|
||||
"If you continue to use the computer without rebooting, "
|
||||
"you may not be able to start new programs which use the "
|
||||
"NVIDIA GPU(s) until after you reboot or reload the NVIDIA "
|
||||
"kernel modules.", reason);
|
||||
}
|
||||
|
||||
nvfree(reason);
|
||||
}
|
||||
|
9
misc.h
9
misc.h
@@ -69,8 +69,10 @@ 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, const RunCommandOutputMatch *match, int redirect);
|
||||
__attribute__((sentinel))
|
||||
int run_command(Options *op, char **data, int output,
|
||||
const RunCommandOutputMatch *match, int redirect,
|
||||
const char *cmd_start, ...);
|
||||
int read_text_file(const char *filename, char **buf);
|
||||
char *find_system_util(const char *util);
|
||||
int find_system_utils(Options *op);
|
||||
@@ -110,5 +112,8 @@ 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);
|
||||
void add_bullet_list_item(const char *new, char **orig);
|
||||
void suggest_reboot(Options *op);
|
||||
int nouveau_is_present(void);
|
||||
|
||||
#endif /* __NVIDIA_INSTALLER_MISC_H__ */
|
||||
|
213
ncurses-ui.c
213
ncurses-ui.c
@@ -69,7 +69,7 @@ typedef struct {
|
||||
|
||||
/*
|
||||
* DataStruct - private data structure that gets plugged into
|
||||
* Options->ui_priv.
|
||||
* Options->ui.priv.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
@@ -91,7 +91,7 @@ typedef struct {
|
||||
|
||||
char *progress_title; /* cached string for the title of the
|
||||
progress messages */
|
||||
|
||||
|
||||
} DataStruct;
|
||||
|
||||
|
||||
@@ -166,6 +166,8 @@ static void nv_ncurses_status_begin (Options*, const char*,
|
||||
const char*);
|
||||
static void nv_ncurses_status_update (Options*, const float,
|
||||
const char*);
|
||||
|
||||
static void nv_ncurses_update_indeterminate(Options*, const char*);
|
||||
static void nv_ncurses_status_end (Options*, const char*);
|
||||
static void nv_ncurses_close (Options*);
|
||||
|
||||
@@ -224,7 +226,6 @@ static void init_position(int p[4], int w);
|
||||
/* misc helper functions */
|
||||
|
||||
static char *nv_ncurses_create_command_list_text(DataStruct *, CommandList *);
|
||||
static char *nv_ncurses_mode_to_permission_string(mode_t);
|
||||
|
||||
static void nv_ncurses_free_text_rows(TextRows *);
|
||||
|
||||
@@ -255,6 +256,7 @@ InstallerUI ui_dispatch_table = {
|
||||
nv_ncurses_status_begin,
|
||||
nv_ncurses_status_update,
|
||||
nv_ncurses_status_end,
|
||||
nv_ncurses_update_indeterminate,
|
||||
nv_ncurses_close
|
||||
};
|
||||
|
||||
@@ -354,9 +356,9 @@ static int nv_ncurses_init(Options *op, FormatTextRows format_text_rows)
|
||||
NV_NCURSES_FOOTER_COLOR,
|
||||
NV_NCURSES_FOOTER_NO_COLOR);
|
||||
|
||||
/* plug the DataStruct struct into the ui_priv pointer */
|
||||
/* plug the DataStruct struct into the ui.priv pointer */
|
||||
|
||||
op->ui_priv = (void *) d;
|
||||
op->ui.priv = (void *) d;
|
||||
|
||||
/* set the initial strings in the header and footer */
|
||||
|
||||
@@ -366,7 +368,7 @@ static int nv_ncurses_init(Options *op, FormatTextRows format_text_rows)
|
||||
NV_NCURSES_DEFAULT_FOOTER_RIGHT);
|
||||
|
||||
wrefresh(nv_stdscr);
|
||||
|
||||
|
||||
return TRUE;
|
||||
|
||||
} /* nv_ncurses_init() */
|
||||
@@ -380,7 +382,7 @@ static int nv_ncurses_init(Options *op, FormatTextRows format_text_rows)
|
||||
|
||||
static void nv_ncurses_set_title(Options *op, const char *title)
|
||||
{
|
||||
DataStruct *d = (DataStruct *) op->ui_priv;
|
||||
DataStruct *d = (DataStruct *) op->ui.priv;
|
||||
|
||||
nv_ncurses_set_header(d, title);
|
||||
|
||||
@@ -403,7 +405,7 @@ static void nv_ncurses_set_title(Options *op, const char *title)
|
||||
static char *nv_ncurses_get_input(Options *op,
|
||||
const char *def, const char *msg)
|
||||
{
|
||||
DataStruct *d = (DataStruct *) op->ui_priv;
|
||||
DataStruct *d = (DataStruct *) op->ui.priv;
|
||||
int msg_len, width, input_len, buf_len, def_len;
|
||||
int input_x, input_y, i, w, h, x, y, c, lines, ch, color, redraw;
|
||||
char *tmp, buf[MAX_BUF_LEN];
|
||||
@@ -639,7 +641,7 @@ static char *nv_ncurses_get_input(Options *op,
|
||||
|
||||
static void nv_ncurses_message(Options *op, int level, const char *msg)
|
||||
{
|
||||
DataStruct *d = (DataStruct *) op->ui_priv;
|
||||
DataStruct *d = (DataStruct *) op->ui.priv;
|
||||
int w, h, x, y, ch;
|
||||
char *prefix;
|
||||
|
||||
@@ -764,7 +766,7 @@ static void nv_ncurses_command_output(Options *op, const char *msg)
|
||||
static int nv_ncurses_approve_command_list(Options *op, CommandList *cl,
|
||||
const char *descr)
|
||||
{
|
||||
DataStruct *d = (DataStruct *) op->ui_priv;
|
||||
DataStruct *d = (DataStruct *) op->ui.priv;
|
||||
char *commandlist, *question;
|
||||
int ret, len;
|
||||
const char *buttons[2] = {"Yes", "No"};
|
||||
@@ -829,7 +831,7 @@ static int nv_ncurses_multiple_choice(Options *op, const char *question,
|
||||
static void nv_ncurses_status_begin(Options *op,
|
||||
const char *title, const char *msg)
|
||||
{
|
||||
DataStruct *d = (DataStruct *) op->ui_priv;
|
||||
DataStruct *d = (DataStruct *) op->ui.priv;
|
||||
|
||||
nv_ncurses_check_resize(d, FALSE);
|
||||
|
||||
@@ -860,12 +862,14 @@ static void nv_ncurses_status_begin(Options *op,
|
||||
static void nv_ncurses_status_update(Options *op, const float percent,
|
||||
const char *msg)
|
||||
{
|
||||
int i, n, h, ch;
|
||||
int i, n, h, ch, w;
|
||||
int p[4];
|
||||
char v[4];
|
||||
DataStruct *d = (DataStruct *) op->ui_priv;
|
||||
DataStruct *d = (DataStruct *) op->ui.priv;
|
||||
int color_offset, color_flag;
|
||||
char status_char;
|
||||
|
||||
/*
|
||||
/*
|
||||
* if the message region was deleted or if the window was resized,
|
||||
* redraw the entire progress bar region.
|
||||
*/
|
||||
@@ -898,7 +902,8 @@ static void nv_ncurses_status_update(Options *op, const float percent,
|
||||
|
||||
/* compute the percentage */
|
||||
|
||||
n = ((int) (percent * (float) (d->message->w - 2)));
|
||||
w = d->message->w - 2;
|
||||
n = ((int) (percent * (float) w));
|
||||
n = NV_MAX(n, 2);
|
||||
|
||||
init_position(p, d->message->w);
|
||||
@@ -913,29 +918,25 @@ static void nv_ncurses_status_update(Options *op, const float percent,
|
||||
/* draw the progress bar */
|
||||
|
||||
if (d->use_color) {
|
||||
for (i = 1; i <= n; i++) {
|
||||
mvwaddch(nv_stdscr, d->message->y + h - 2, d->message->x + i,
|
||||
choose_char(i, p, v,' ') |
|
||||
A_REVERSE | NV_NCURSES_INPUT_COLOR);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (p[i] >= (n+1)) {
|
||||
mvwaddch(nv_stdscr, d->message->y + h - 2, d->message->x + p[i],
|
||||
(v[i] ? v[i] : ' ') | NV_NCURSES_INPUT_COLOR);
|
||||
}
|
||||
}
|
||||
color_offset = 0;
|
||||
color_flag = NV_NCURSES_INPUT_COLOR;
|
||||
status_char = ' ';
|
||||
} else {
|
||||
for (i = 2; i < n; i++) {
|
||||
mvwaddch(nv_stdscr, d->message->y + h - 2, d->message->x + i,
|
||||
choose_char(i, p, v, ' ') | A_REVERSE);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (p[i] >= n) {
|
||||
mvwaddch(nv_stdscr, d->message->y + h - 2, d->message->x + p[i],
|
||||
v[i] ? v[i] : '-');
|
||||
}
|
||||
color_offset = 1;
|
||||
color_flag = 0;
|
||||
status_char = '-';
|
||||
}
|
||||
|
||||
for (i = 1 + color_offset; i <= w - color_offset; i++) {
|
||||
int reverse_flag = i > n - color_offset ? 0 : A_REVERSE;
|
||||
mvwaddch(nv_stdscr, d->message->y + h - 2, d->message->x + i,
|
||||
choose_char(i, p, v, ' ') | reverse_flag | color_flag);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (p[i] >= n + 1 - color_offset) {
|
||||
mvwaddch(nv_stdscr, d->message->y + h - 2, d->message->x + p[i],
|
||||
(v[i] ? v[i] : status_char) | color_flag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -944,6 +945,44 @@ static void nv_ncurses_status_update(Options *op, const float percent,
|
||||
} /* nv_ncurses_status_update() */
|
||||
|
||||
|
||||
static void nv_ncurses_update_indeterminate(Options *op, const char *msg)
|
||||
{
|
||||
DataStruct *d = op->ui.priv;
|
||||
static uint32_t pattern = 0x7ff;
|
||||
int x;
|
||||
|
||||
if (nv_ncurses_check_resize(d, FALSE) || !d->message) {
|
||||
if (d->message) nv_ncurses_destroy_region(d->message);
|
||||
nv_ncurses_do_progress_bar_region(d);
|
||||
}
|
||||
|
||||
nv_ncurses_do_progress_bar_message(d, msg, d->message->h - 3,
|
||||
d->message->w - 2);
|
||||
|
||||
for (x = 1; x < d->message->w - 1; x++) {
|
||||
int color_flag;
|
||||
|
||||
if (d->use_color) {
|
||||
color_flag = NV_NCURSES_INPUT_COLOR;
|
||||
} else {
|
||||
color_flag = 0;
|
||||
}
|
||||
|
||||
if (pattern & (1 << (x % 32))) {
|
||||
color_flag |= A_REVERSE;
|
||||
}
|
||||
|
||||
mvwaddch(nv_stdscr, d->message->y + d->message->h - 2,
|
||||
d->message->x + x, ' ' | color_flag);
|
||||
}
|
||||
|
||||
wrefresh(nv_stdscr);
|
||||
|
||||
pattern = pattern << 1 | (pattern >> 31 & 1);
|
||||
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@@ -955,7 +994,7 @@ static void nv_ncurses_status_end(Options *op, const char *msg)
|
||||
int i, n, h;
|
||||
int p[4];
|
||||
char v[4];
|
||||
DataStruct *d = (DataStruct *) op->ui_priv;
|
||||
DataStruct *d = (DataStruct *) op->ui.priv;
|
||||
|
||||
/*
|
||||
* if the message region was deleted or if the window was resized,
|
||||
@@ -1018,7 +1057,7 @@ static void nv_ncurses_close(Options *op)
|
||||
|
||||
/* XXX op may be NULL if we get called from a signal handler */
|
||||
|
||||
d = (DataStruct *) op->ui_priv;
|
||||
d = (DataStruct *) op->ui.priv;
|
||||
nv_ncurses_destroy_region(d->header);
|
||||
nv_ncurses_destroy_region(d->footer);
|
||||
free(d);
|
||||
@@ -1028,10 +1067,7 @@ static void nv_ncurses_close(Options *op)
|
||||
wrefresh(nv_stdscr);
|
||||
|
||||
endwin(); /* End curses mode */
|
||||
|
||||
return;
|
||||
|
||||
} /* nv_ncurses_close() */
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1606,7 +1642,7 @@ static int nv_ncurses_paged_prompt(Options *op, const char *question,
|
||||
const char * const *buttons,
|
||||
int num_buttons, int default_button)
|
||||
{
|
||||
DataStruct *d = (DataStruct *) op->ui_priv;
|
||||
DataStruct *d = (DataStruct *) op->ui.priv;
|
||||
TextRows *t_pager = NULL;
|
||||
int ch, cur = 0;
|
||||
int i, button_w = 0, button_y, button = default_button;
|
||||
@@ -1823,63 +1859,11 @@ static void init_position(int p[4], int w)
|
||||
|
||||
static char *nv_ncurses_create_command_list_text(DataStruct *d, CommandList *cl)
|
||||
{
|
||||
int i, len;
|
||||
Command *c;
|
||||
char *str, *perms, *ret = strdup("");
|
||||
char *ret = strdup("");
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cl->num; i++) {
|
||||
c = &cl->cmds[i];
|
||||
|
||||
str = NULL;
|
||||
|
||||
switch (c->cmd) {
|
||||
|
||||
case INSTALL_CMD:
|
||||
perms = nv_ncurses_mode_to_permission_string(c->mode);
|
||||
len = strlen(c->s0) + strlen(c->s1) + strlen(perms) + 64;
|
||||
if (c->s2) {
|
||||
len += strlen(c->s2) + 64;
|
||||
}
|
||||
str = (char *) malloc(len + 1);
|
||||
snprintf(str, len, "Install the file '%s' as '%s' with "
|
||||
"permissions '%s'", c->s0, c->s1, perms);
|
||||
free(perms);
|
||||
if (c->s2) {
|
||||
len = strlen(c->s2) + 64;
|
||||
snprintf(str + strlen(str), len,
|
||||
" then execute the command `%s`", c->s2);
|
||||
}
|
||||
break;
|
||||
|
||||
case RUN_CMD:
|
||||
len = strlen(c->s0) + 64;
|
||||
str = (char *) malloc(len + 1);
|
||||
snprintf(str, len, "Execute the command `%s`", c->s0);
|
||||
break;
|
||||
|
||||
case SYMLINK_CMD:
|
||||
len = strlen(c->s0) + strlen(c->s1) + 64;
|
||||
str = (char *) malloc(len + 1);
|
||||
snprintf(str, len, "Create a symbolic link '%s' to '%s'",
|
||||
c->s0, c->s1);
|
||||
break;
|
||||
|
||||
case BACKUP_CMD:
|
||||
len = strlen(c->s0) + 64;
|
||||
str = (char *) malloc(len + 1);
|
||||
snprintf(str, len, "Back up the file '%s'", c->s0);
|
||||
break;
|
||||
|
||||
case DELETE_CMD:
|
||||
len = strlen(c->s0) + 64;
|
||||
str = (char *) malloc(len + 1);
|
||||
snprintf(str, len, "Delete the file '%s'", c->s0);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* XXX should not get here */
|
||||
break;
|
||||
}
|
||||
const char *str = cl->descriptions[i];
|
||||
|
||||
if (str) {
|
||||
int lenret, lenstr;
|
||||
@@ -1897,46 +1881,15 @@ static char *nv_ncurses_create_command_list_text(DataStruct *d, CommandList *cl)
|
||||
tmp[lenret + lenstr] = '\n';
|
||||
tmp[lenret + lenstr + 1] = 0;
|
||||
|
||||
free(str);
|
||||
free(ret);
|
||||
ret = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* mode_to_permission_string() - given a mode bitmask, allocate and
|
||||
* write a permission string.
|
||||
*/
|
||||
|
||||
static char *nv_ncurses_mode_to_permission_string(mode_t mode)
|
||||
{
|
||||
char *s = (char *) malloc(10);
|
||||
memset (s, '-', 9);
|
||||
|
||||
if (mode & (1 << 8)) s[0] = 'r';
|
||||
if (mode & (1 << 7)) s[1] = 'w';
|
||||
if (mode & (1 << 6)) s[2] = 'x';
|
||||
|
||||
if (mode & (1 << 5)) s[3] = 'r';
|
||||
if (mode & (1 << 4)) s[4] = 'w';
|
||||
if (mode & (1 << 3)) s[5] = 'x';
|
||||
|
||||
if (mode & (1 << 2)) s[6] = 'r';
|
||||
if (mode & (1 << 1)) s[7] = 'w';
|
||||
if (mode & (1 << 0)) s[8] = 'x';
|
||||
|
||||
s[9] = '\0';
|
||||
return s;
|
||||
|
||||
} /* mode_to_permission_string() */
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* nv_free_text_rows() - free the TextRows data structure allocated by
|
||||
|
@@ -147,16 +147,25 @@ typedef struct __nv_installer_ui {
|
||||
int default_answer);
|
||||
|
||||
/*
|
||||
* status_begin(), status_update(), status_end() - these three
|
||||
* functions display the status of some process. It is expected
|
||||
* status_begin(), status_update(), status_end() -
|
||||
* these functions display the status of some process. It is expected
|
||||
* that status_begin() would be called, followed by some number of
|
||||
* status_update() calls, followed by a status_end() call.
|
||||
* status_update() and/or ui_indeterminate_begin/end() calls, followed by
|
||||
* a status_end() call.
|
||||
*/
|
||||
|
||||
void (*status_begin)(Options *op, const char *title, const char *msg);
|
||||
void (*status_update)(Options *op, const float percent, const char *msg);
|
||||
void (*status_end)(Options *op, const char *msg);
|
||||
|
||||
/*
|
||||
* update_indeterminate() - this is called in a loop by a worker thread
|
||||
* which is started by ui_indeterminate_begin. The worker stays alive as
|
||||
* long as the indeterminate state is active. The loop breaks when the next
|
||||
* ui_indeterminate_end() call sets the state to inactive.
|
||||
*/
|
||||
void (*update_indeterminate)(Options *, const char *msg);
|
||||
|
||||
/*
|
||||
* close - close down the ui.
|
||||
*/
|
||||
|
@@ -44,6 +44,7 @@
|
||||
#include "option_table.h"
|
||||
#include "msg.h"
|
||||
#include "manifest.h"
|
||||
#include "initramfs.h"
|
||||
|
||||
static void print_version(void);
|
||||
static void print_help(const char* name, int is_uninstall, int advanced);
|
||||
@@ -146,6 +147,8 @@ static Options *load_default_options(void)
|
||||
op->external_platform_json_path = DEFAULT_EGL_EXTERNAL_PLATFORM_JSON_PATH;
|
||||
op->skip_depmod = FALSE;
|
||||
op->use_systemd = NV_OPTIONAL_BOOL_DEFAULT;
|
||||
op->rebuild_initramfs = NV_OPTIONAL_BOOL_DEFAULT;
|
||||
op->disable_nouveau = TRUE;
|
||||
|
||||
return op;
|
||||
|
||||
@@ -227,7 +230,7 @@ static void parse_commandline(int argc, char *argv[], Options *op)
|
||||
case 'd': op->debug = TRUE; break;
|
||||
case 'i':
|
||||
op->driver_info = TRUE;
|
||||
op->ui_str = "none";
|
||||
op->ui.name = "none";
|
||||
break;
|
||||
case 'n': op->no_precompiled_interface = TRUE; break;
|
||||
case 'c': op->no_ncurses_color = TRUE; break;
|
||||
@@ -245,10 +248,10 @@ static void parse_commandline(int argc, char *argv[], Options *op)
|
||||
case 'X': op->run_nvidia_xconfig = TRUE; break;
|
||||
case 's':
|
||||
op->silent = op->no_questions = TRUE;
|
||||
op->ui_str = "none";
|
||||
op->ui.name = "none";
|
||||
break;
|
||||
case 'z': op->no_nouveau_check = TRUE; break;
|
||||
case 'Z': op->disable_nouveau = TRUE; break;
|
||||
case 'Z': op->disable_nouveau = boolval; break;
|
||||
case 'k':
|
||||
op->kernel_name = strval;
|
||||
op->no_precompiled_interface = TRUE;
|
||||
@@ -319,7 +322,7 @@ static void parse_commandline(int argc, char *argv[], Options *op)
|
||||
case PROC_MOUNT_POINT_OPTION:
|
||||
op->proc_mount_point = strval; break;
|
||||
case USER_INTERFACE_OPTION:
|
||||
op->ui_str = strval; break;
|
||||
op->ui.name = strval; break;
|
||||
case LOG_FILE_NAME_OPTION:
|
||||
op->log_file_name = strval; break;
|
||||
case HELP_ARGS_ONLY_OPTION:
|
||||
@@ -520,6 +523,13 @@ static void parse_commandline(int argc, char *argv[], Options *op)
|
||||
case 'm':
|
||||
op->kernel_module_build_directory_override = strval;
|
||||
break;
|
||||
case ALLOW_INSTALLATION_WITH_RUNNING_DRIVER_OPTION:
|
||||
op->allow_installation_with_running_driver = boolval;
|
||||
break;
|
||||
case REBUILD_INITRAMFS_OPTION:
|
||||
op->rebuild_initramfs = boolval ? NV_OPTIONAL_BOOL_TRUE :
|
||||
NV_OPTIONAL_BOOL_FALSE;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
@@ -613,6 +623,10 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (!ui_init(op)) return 1;
|
||||
|
||||
if (!begin_initramfs_scan(op)) {
|
||||
ui_log(op, "Failed to initiate initramfs scan");
|
||||
}
|
||||
|
||||
/* determine the concurrency level: do this early on, to allow for
|
||||
* parallelization of as much of the install as possible. */
|
||||
|
||||
@@ -675,6 +689,10 @@ int main(int argc, char *argv[])
|
||||
ret = install_from_cwd(op);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
suggest_reboot(op);
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
ui_close(op);
|
||||
|
@@ -171,7 +171,7 @@ typedef uint32_t uint32;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint8_t uint8;
|
||||
|
||||
|
||||
typedef struct __indeterminate_data IndeterminateData;
|
||||
|
||||
/*
|
||||
* Options structure; malloced by and initialized by
|
||||
@@ -224,10 +224,14 @@ typedef struct __options {
|
||||
int concurrency_level;
|
||||
int skip_module_load;
|
||||
int skip_depmod;
|
||||
int allow_installation_with_running_driver;
|
||||
int loaded_kernel_module_detected;
|
||||
int running_x_server_detected;
|
||||
|
||||
NVOptionalBool install_libglx_indirect;
|
||||
NVOptionalBool install_libglvnd_libraries;
|
||||
NVOptionalBool install_compat32_libs;
|
||||
NVOptionalBool rebuild_initramfs;
|
||||
|
||||
char *file_type_destination_overrides[FILE_TYPE_MAX];
|
||||
|
||||
@@ -276,7 +280,6 @@ typedef struct __options {
|
||||
char *utils[MAX_UTILS];
|
||||
|
||||
char *proc_mount_point;
|
||||
char *ui_str;
|
||||
char *log_file_name;
|
||||
|
||||
char *tmpdir;
|
||||
@@ -299,8 +302,6 @@ typedef struct __options {
|
||||
int kernel_module_signed;
|
||||
int dkms_registered;
|
||||
|
||||
void *ui_priv; /* for use by the ui's */
|
||||
|
||||
NVOptionalBool use_systemd;
|
||||
char *systemd_unit_prefix;
|
||||
char *systemd_sleep_prefix;
|
||||
@@ -308,6 +309,12 @@ typedef struct __options {
|
||||
|
||||
char *kernel_module_build_directory_override;
|
||||
|
||||
struct {
|
||||
char *name;
|
||||
void *priv;
|
||||
int status_active;
|
||||
IndeterminateData *indeterminate_data;
|
||||
} ui;
|
||||
} Options;
|
||||
|
||||
typedef enum {
|
||||
@@ -428,7 +435,6 @@ typedef struct __package {
|
||||
char *description;
|
||||
char *version;
|
||||
char *kernel_module_build_directory;
|
||||
char *precompiled_kernel_interface_directory;
|
||||
char *kernel_make_logs;
|
||||
|
||||
PackageEntry *entries; /* array of filename/checksum/bytesize entries */
|
||||
|
@@ -116,6 +116,8 @@ enum {
|
||||
SYSTEMD_SLEEP_PREFIX_OPTION,
|
||||
SYSTEMD_SYSCONF_PREFIX_OPTION,
|
||||
GBM_BACKEND_DIR_OPTION,
|
||||
ALLOW_INSTALLATION_WITH_RUNNING_DRIVER_OPTION,
|
||||
REBUILD_INITRAMFS_OPTION,
|
||||
};
|
||||
|
||||
static const NVGetoptOption __options[] = {
|
||||
@@ -474,11 +476,11 @@ static const NVGetoptOption __options[] = {
|
||||
"Normally, nvidia-installer aborts installation if the nouveau kernel "
|
||||
"driver is in use. Use this option to disable this check." },
|
||||
|
||||
{ "disable-nouveau", 'Z', 0, NULL,
|
||||
"If the nouveau kernel module is detected by nvidia-installer, the "
|
||||
"installer offers to attempt to disable nouveau. The default action "
|
||||
"is to not attempt to disable nouveau; use this option to change the "
|
||||
"default action to attempt to disable nouveau."},
|
||||
{ "disable-nouveau", 'Z', NVGETOPT_IS_BOOLEAN, NULL,
|
||||
"nvidia-installer will attempt to disable the nouveau kernel driver "
|
||||
"by default, if it is in use during installation. Use "
|
||||
"'--no-disable-nouveau to prevent nvidia-installer from disabling "
|
||||
"nouveau by default."},
|
||||
|
||||
{ "run-nvidia-xconfig", 'X', 0, NULL,
|
||||
"nvidia-installer can optionally invoke the nvidia-xconfig utility. "
|
||||
@@ -714,6 +716,22 @@ static const NVGetoptOption __options[] = {
|
||||
"build files is normally 'kernel/'. This option can be used to "
|
||||
"override this value." },
|
||||
|
||||
{ "allow-installation-with-running-driver",
|
||||
ALLOW_INSTALLATION_WITH_RUNNING_DRIVER_OPTION, NVGETOPT_IS_BOOLEAN, NULL,
|
||||
"Proceed with installation even if an NVIDIA driver is already installed "
|
||||
"and running."
|
||||
},
|
||||
|
||||
{ "rebuild-initramfs",
|
||||
REBUILD_INITRAMFS_OPTION, NVGETOPT_IS_BOOLEAN, NULL,
|
||||
"Rebuild the initramfs after installation is complete, regardless of the "
|
||||
"default action recommended by nvidia-installer. --no-rebuild-initramfs "
|
||||
"skips rebuilding the initramfs after installation is complete. These "
|
||||
"options are useful for non-interactive installations when a specific "
|
||||
"behavior is desired, regardless of what nvidia-installer would "
|
||||
"recommend by default in an interactive installation."
|
||||
},
|
||||
|
||||
/* Orphaned options: These options were in the long_options table in
|
||||
* nvidia-installer.c but not in the help. */
|
||||
{ "debug", 'd', 0, NULL,NULL },
|
||||
|
153
stream-ui.c
153
stream-ui.c
@@ -27,6 +27,7 @@
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "nvidia-installer.h"
|
||||
#include "nvidia-installer-ui.h"
|
||||
@@ -52,6 +53,7 @@ int stream_paged_prompt (Options *op, const char *, const char *,
|
||||
void stream_status_begin (Options*, const char*, const char*);
|
||||
void stream_status_update (Options*, const float, const char*);
|
||||
void stream_status_end (Options*, const char*);
|
||||
void stream_update_indeterminate(Options*, const char*);
|
||||
void stream_close (Options*);
|
||||
|
||||
InstallerUI stream_ui_dispatch_table = {
|
||||
@@ -68,13 +70,13 @@ InstallerUI stream_ui_dispatch_table = {
|
||||
stream_status_begin,
|
||||
stream_status_update,
|
||||
stream_status_end,
|
||||
stream_update_indeterminate,
|
||||
stream_close
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
int status_active;
|
||||
char *status_label;
|
||||
float percent;
|
||||
} Data;
|
||||
|
||||
|
||||
@@ -82,6 +84,7 @@ typedef struct {
|
||||
#define STATUS_BEGIN 0
|
||||
#define STATUS_UPDATE 1
|
||||
#define STATUS_END 2
|
||||
#define STATUS_INDETERMINATE 3
|
||||
|
||||
#define STATUS_BAR_WIDTH 30
|
||||
|
||||
@@ -94,21 +97,48 @@ static void print_status_bar(Data *d, int status, float percent)
|
||||
int i;
|
||||
float val;
|
||||
|
||||
if (status != STATUS_BEGIN) printf("\r");
|
||||
|
||||
if (d->status_label) {
|
||||
printf(" %s: [", d->status_label);
|
||||
} else {
|
||||
printf(" [");
|
||||
static int indeterminate_position;
|
||||
|
||||
switch (status) {
|
||||
case STATUS_BEGIN:
|
||||
/* reset the position of the indeterminate progress indicator */
|
||||
indeterminate_position = 0;
|
||||
break;
|
||||
case STATUS_UPDATE:
|
||||
case STATUS_END:
|
||||
case STATUS_INDETERMINATE:
|
||||
default:
|
||||
printf("\r");
|
||||
break;
|
||||
}
|
||||
|
||||
printf(" [");
|
||||
|
||||
val = ((float) STATUS_BAR_WIDTH * percent);
|
||||
|
||||
for (i = 0; i < STATUS_BAR_WIDTH; i++) {
|
||||
printf("%c", ((float) i < val) ? '#' : ' ');
|
||||
char c;
|
||||
|
||||
if (status == STATUS_INDETERMINATE) {
|
||||
c = (i == indeterminate_position % STATUS_BAR_WIDTH) ? '#' : ' ';
|
||||
} else {
|
||||
c = (float) i < val ? '#' : ' ';
|
||||
}
|
||||
|
||||
printf("%c", c);
|
||||
}
|
||||
|
||||
printf("] %3d%%", (int) (percent * 100.0));
|
||||
indeterminate_position++;
|
||||
|
||||
printf("] ");
|
||||
if (status == STATUS_INDETERMINATE) {
|
||||
/* Clear any existing percentage display and rewind the cursor to
|
||||
* just after the ']' printed above */
|
||||
printf(" \b\b\b\b\b");
|
||||
} else {
|
||||
/* Display the current percentage */
|
||||
printf("%3d%%", (int) (percent * 100.0));
|
||||
}
|
||||
|
||||
if (status == STATUS_END) printf("\n");
|
||||
|
||||
@@ -145,8 +175,7 @@ int stream_init(Options *op, FormatTextRows format_text_rows)
|
||||
{
|
||||
Data *d = nvalloc(sizeof(Data));
|
||||
|
||||
d->status_active = FALSE;
|
||||
op->ui_priv = d;
|
||||
op->ui.priv = d;
|
||||
|
||||
if (!op->silent) {
|
||||
|
||||
@@ -225,12 +254,10 @@ void stream_message(Options *op, const int level, const char *msg)
|
||||
{ "WARNING: ", stderr, TRUE }, /* NV_MSG_LEVEL_WARNING */
|
||||
{ "ERROR: ", stderr, TRUE } /* NV_MSG_LEVEL_ERROR */
|
||||
};
|
||||
|
||||
Data *d = op->ui_priv;
|
||||
|
||||
/* don't print log messages if we're currently displaying a status */
|
||||
|
||||
if ((level == NV_MSG_LEVEL_LOG) && (d->status_active)) return;
|
||||
if ((level == NV_MSG_LEVEL_LOG) && (op->ui.status_active)) return;
|
||||
|
||||
if (msg_attrs[level].newline) {
|
||||
nv_info_msg_to_file(msg_attrs[level].stream, NULL, "");
|
||||
@@ -255,9 +282,7 @@ void stream_message(Options *op, const int level, const char *msg)
|
||||
|
||||
void stream_command_output(Options *op, const char *msg)
|
||||
{
|
||||
Data *d = op->ui_priv;
|
||||
|
||||
if ((!op->expert) || (d->status_active)) return;
|
||||
if ((!op->expert) || (op->ui.status_active)) return;
|
||||
|
||||
nv_info_msg(" ", "%s", msg);
|
||||
|
||||
@@ -274,8 +299,6 @@ int stream_approve_command_list(Options *op, CommandList *cl,
|
||||
const char *descr)
|
||||
{
|
||||
int i;
|
||||
Command *c;
|
||||
char *perms;
|
||||
const char *prefix = " --> ";
|
||||
|
||||
nv_info_msg(NULL, "");
|
||||
@@ -284,50 +307,11 @@ int stream_approve_command_list(Options *op, CommandList *cl,
|
||||
nv_info_msg(NULL, "");
|
||||
|
||||
for (i = 0; i < cl->num; i++) {
|
||||
c = &cl->cmds[i];
|
||||
|
||||
switch (c->cmd) {
|
||||
|
||||
case INSTALL_CMD:
|
||||
perms = mode_to_permission_string(c->mode);
|
||||
nv_info_msg(prefix, "install the file '%s' as '%s' with "
|
||||
"permissions '%s'", c->s0, c->s1, perms);
|
||||
free(perms);
|
||||
if (c->s2) {
|
||||
nv_info_msg(prefix, "execute the command `%s`", c->s2);
|
||||
}
|
||||
break;
|
||||
|
||||
case RUN_CMD:
|
||||
nv_info_msg(prefix, "execute the command `%s`", c->s0);
|
||||
break;
|
||||
|
||||
case SYMLINK_CMD:
|
||||
nv_info_msg(prefix, "create a symbolic link '%s' to '%s'",
|
||||
c->s0, c->s1);
|
||||
break;
|
||||
|
||||
case BACKUP_CMD:
|
||||
nv_info_msg(prefix, "back up the file '%s'", c->s0);
|
||||
break;
|
||||
|
||||
case DELETE_CMD:
|
||||
nv_info_msg(prefix, "delete file '%s'", c->s0);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
nv_error_msg("Error in CommandList! (cmd: %d; s0: '%s';"
|
||||
"s1: '%s'; s2: '%s'; mode: %04o)",
|
||||
c->cmd, c->s0, c->s1, c->s2, c->mode);
|
||||
nv_error_msg("Aborting installation.");
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
nv_info_msg(prefix, "%s", cl->descriptions[i]);
|
||||
}
|
||||
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
|
||||
if (!stream_yes_no(op, TRUE, "\nIs this acceptable? (answering 'no' will "
|
||||
"abort installation)")) {
|
||||
nv_error_msg("Command list not accepted; exiting installation.");
|
||||
@@ -335,7 +319,7 @@ int stream_approve_command_list(Options *op, CommandList *cl,
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
|
||||
} /* stream_approve_command_list() */
|
||||
|
||||
|
||||
@@ -486,15 +470,14 @@ int stream_paged_prompt(Options *op, const char *question,
|
||||
|
||||
void stream_status_begin(Options *op, const char *title, const char *msg)
|
||||
{
|
||||
Data *d = op->ui_priv;
|
||||
|
||||
d->status_active = TRUE;
|
||||
|
||||
nv_info_msg(NULL, "%s", title);
|
||||
d->status_label = nvstrdup(msg);
|
||||
Data *d = op->ui.priv;
|
||||
|
||||
d->percent = 0;
|
||||
|
||||
nv_info_msg(NULL, "%s: %s\n", title, msg ? msg : "");
|
||||
|
||||
print_status_bar(d, STATUS_BEGIN, 0.0);
|
||||
|
||||
|
||||
} /* stream_status_begin() */
|
||||
|
||||
|
||||
@@ -505,11 +488,24 @@ void stream_status_begin(Options *op, const char *title, const char *msg)
|
||||
|
||||
void stream_status_update(Options *op, const float percent, const char *msg)
|
||||
{
|
||||
print_status_bar(op->ui_priv, STATUS_UPDATE, percent);
|
||||
Data *d = op->ui.priv;
|
||||
|
||||
if (d->percent != percent) {
|
||||
d->percent = percent;
|
||||
print_status_bar(op->ui.priv, STATUS_UPDATE, percent);
|
||||
}
|
||||
|
||||
} /* stream_status_update() */
|
||||
|
||||
|
||||
void stream_update_indeterminate(Options *op, const char *msg)
|
||||
{
|
||||
Data *d = op->ui.priv;
|
||||
|
||||
print_status_bar(d, STATUS_INDETERMINATE, 0.0);
|
||||
usleep(250000);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* stream_status_end() -
|
||||
@@ -517,13 +513,7 @@ void stream_status_update(Options *op, const float percent, const char *msg)
|
||||
|
||||
void stream_status_end(Options *op, const char *msg)
|
||||
{
|
||||
Data *d = op->ui_priv;
|
||||
|
||||
print_status_bar(op->ui_priv, STATUS_END, 1.0);
|
||||
|
||||
nvfree(d->status_label);
|
||||
d->status_active = FALSE;
|
||||
|
||||
print_status_bar(op->ui.priv, STATUS_END, 1.0);
|
||||
} /* stream_status_end() */
|
||||
|
||||
|
||||
@@ -534,6 +524,7 @@ void stream_status_end(Options *op, const char *msg)
|
||||
|
||||
void stream_close(Options *op)
|
||||
{
|
||||
return;
|
||||
|
||||
} /* stream_close() */
|
||||
if (op) {
|
||||
nvfree(op->ui.priv);
|
||||
}
|
||||
}
|
||||
|
125
ui-status-indeterminate.c
Normal file
125
ui-status-indeterminate.c
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) 2023 NVIDIA Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "ui-status-indeterminate.h"
|
||||
|
||||
struct __indeterminate_data {
|
||||
pthread_mutex_t mutex;
|
||||
pthread_t thread;
|
||||
IndeterminateState state;
|
||||
};
|
||||
|
||||
/* Allocate an IndeterminateData and initialize its mutex */
|
||||
|
||||
IndeterminateData *indeterminate_init(void)
|
||||
{
|
||||
IndeterminateData *ret = calloc(1, sizeof(*ret));
|
||||
|
||||
if (ret) {
|
||||
if (pthread_mutex_init(&ret->mutex, NULL) == 0) {
|
||||
ret->state = INDETERMINATE_INACTIVE;
|
||||
} else {
|
||||
ret->state = INDETERMINATE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Clean up IndeterminateData resources */
|
||||
|
||||
void indeterminate_destroy(IndeterminateData *d)
|
||||
{
|
||||
if (d) {
|
||||
if (d->state != INDETERMINATE_INVALID) {
|
||||
pthread_mutex_destroy(&d->mutex);
|
||||
}
|
||||
free(d);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the current state of the indeterminate progress bar */
|
||||
|
||||
IndeterminateState indeterminate_get(IndeterminateData *d)
|
||||
{
|
||||
IndeterminateState state = INDETERMINATE_INVALID;
|
||||
|
||||
if (d && d->state != INDETERMINATE_INVALID) {
|
||||
if (!pthread_mutex_lock(&d->mutex)) {
|
||||
state = d->state;
|
||||
if (pthread_mutex_unlock(&d->mutex)) {
|
||||
state = INDETERMINATE_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static void indeterminate_set(IndeterminateData *d, IndeterminateState state)
|
||||
{
|
||||
if (!d || d->state == INDETERMINATE_INVALID) {
|
||||
return;
|
||||
} else if (pthread_mutex_lock(&d->mutex)) {
|
||||
d->state = INDETERMINATE_INVALID;
|
||||
return;
|
||||
}
|
||||
|
||||
d->state = state;
|
||||
|
||||
if (pthread_mutex_unlock(&d->mutex)) {
|
||||
d->state = INDETERMINATE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
/* Begin displaying a new indeterminate indicator, replacing any existing bar */
|
||||
|
||||
void indeterminate_begin(IndeterminateData *d, void *(*worker)(void *),
|
||||
void *args)
|
||||
{
|
||||
if (!d || indeterminate_get(d) == INDETERMINATE_INVALID) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Finish any existing indeterminate progress indicator */
|
||||
indeterminate_end(d);
|
||||
|
||||
if (pthread_create(&d->thread, NULL, worker, args)) {
|
||||
indeterminate_set(d, INDETERMINATE_INVALID);
|
||||
} else {
|
||||
indeterminate_set(d, INDETERMINATE_ACTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Stop the indeterminate progress bar and wait for it to finish updating */
|
||||
|
||||
void indeterminate_end(IndeterminateData *d)
|
||||
{
|
||||
void *join_ret;
|
||||
|
||||
if (!d || indeterminate_get(d) != INDETERMINATE_ACTIVE) {
|
||||
return;
|
||||
}
|
||||
|
||||
indeterminate_set(d, INDETERMINATE_INACTIVE);
|
||||
|
||||
if (pthread_join(d->thread, &join_ret)) {
|
||||
indeterminate_set(d, INDETERMINATE_INVALID);
|
||||
}
|
||||
}
|
48
ui-status-indeterminate.h
Normal file
48
ui-status-indeterminate.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2023 NVIDIA Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
#ifndef __UI_STATUS_INDETERMINATE_H__
|
||||
#define __UI_STATUS_INDETERMINATE_H__
|
||||
|
||||
/*
|
||||
* Current state of the indeterminate status indicator, if any:
|
||||
*
|
||||
* INDETERMINATE_INVALID: The indeterminate status indicator is broken. All of
|
||||
* the indeterminate functions should be no-ops.
|
||||
* INDETERMINATE_INACTIVE: The task which the indeterminate status indicator is
|
||||
* tracking has not been started or is complete.
|
||||
* INDETERMINATE_ACTIVE: The task which the indeterminate status indicator is
|
||||
* tracking is actively running.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
INDETERMINATE_INVALID,
|
||||
INDETERMINATE_INACTIVE,
|
||||
INDETERMINATE_ACTIVE,
|
||||
} IndeterminateState;
|
||||
|
||||
/*
|
||||
* Opaque object used by callers
|
||||
*/
|
||||
|
||||
typedef struct __indeterminate_data IndeterminateData;
|
||||
|
||||
IndeterminateData *indeterminate_init(void);
|
||||
void indeterminate_destroy(IndeterminateData *d);
|
||||
IndeterminateState indeterminate_get(IndeterminateData *d);
|
||||
void indeterminate_begin(IndeterminateData *d, void *(*w)(void *), void *args);
|
||||
void indeterminate_end(IndeterminateData *d);
|
||||
#endif
|
@@ -38,6 +38,7 @@
|
||||
#include "misc.h"
|
||||
#include "files.h"
|
||||
#include "user-interface.h"
|
||||
#include "ui-status-indeterminate.h"
|
||||
|
||||
/*
|
||||
* global user interface pointer
|
||||
@@ -124,15 +125,15 @@ int ui_init(Options *op)
|
||||
__ui = NULL;
|
||||
|
||||
if (!op->silent) {
|
||||
if (op->ui_str) {
|
||||
if (op->ui.name) {
|
||||
for (i = 0; i < ARRAY_LEN(ui_list); i++) {
|
||||
if (strcmp(op->ui_str, ui_list[i].name) == 0) {
|
||||
if (strcmp(op->ui.name, ui_list[i].name) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ARRAY_LEN(ui_list)) {
|
||||
log_printf(op, NULL, "Invalid \"ui\" option: %s", op->ui_str);
|
||||
log_printf(op, NULL, "Invalid \"ui\" option: %s", op->ui.name);
|
||||
i = 0;
|
||||
}
|
||||
} else {
|
||||
@@ -180,6 +181,8 @@ int ui_init(Options *op)
|
||||
|
||||
if (!__ui->init(op, nv_format_text_rows)) return FALSE;
|
||||
|
||||
op->ui.indeterminate_data = indeterminate_init();
|
||||
|
||||
/* handle some common signals */
|
||||
|
||||
signal(SIGHUP, ui_signal_handler);
|
||||
@@ -463,6 +466,15 @@ int ui_paged_prompt (Options *op, const char *question, const char *pager_title,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ui_status_begin(): create a new status indicator and displays it immediately
|
||||
*
|
||||
* title: a title that will be displayed for the life of the status indicator.
|
||||
* fmt, ...: a printf(3)-style message which may be replaced by other messages
|
||||
* during the life of the status indicator. This argument is optional
|
||||
* and may be passed NULL.
|
||||
*/
|
||||
|
||||
void ui_status_begin(Options *op, const char *title, const char *fmt, ...)
|
||||
{
|
||||
char *msg;
|
||||
@@ -473,11 +485,20 @@ void ui_status_begin(Options *op, const char *title, const char *fmt, ...)
|
||||
|
||||
NV_VSNPRINTF(msg, fmt);
|
||||
|
||||
op->ui.status_active = TRUE;
|
||||
|
||||
__ui->status_begin(op, title, msg);
|
||||
free(msg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ui_status_update(): update the position of the status indicator
|
||||
*
|
||||
* percent: a number from 0.0 to 1.0 indicating the level of completion
|
||||
* fmt, ...: replaces any previously displayed status message; note that some
|
||||
* UI implementations (e.g. stream) may only display the initial
|
||||
* message, if any, that was provided with ui_status_begin().
|
||||
*/
|
||||
|
||||
void ui_status_update(Options *op, const float percent, const char *fmt, ...)
|
||||
{
|
||||
@@ -491,8 +512,62 @@ void ui_status_update(Options *op, const float percent, const char *fmt, ...)
|
||||
free(msg);
|
||||
}
|
||||
|
||||
struct indeterminate_args {
|
||||
Options *op;
|
||||
char *msg;
|
||||
};
|
||||
|
||||
static void *indeterminate_worker(void *p)
|
||||
{
|
||||
struct indeterminate_args *args = p;
|
||||
Options *op = args->op;
|
||||
char *msg = nvstrdup(args->msg);
|
||||
IndeterminateData *id = op->ui.indeterminate_data;
|
||||
|
||||
while (indeterminate_get(id) == INDETERMINATE_ACTIVE) {
|
||||
__ui->update_indeterminate(op, msg);
|
||||
}
|
||||
|
||||
nvfree(msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ui_indeterminate_begin(): display an "indeterminate" status indicator for
|
||||
* a task with an unknown completion point. This indicator will be shown until
|
||||
* it is ended with ui_indeterminate_end();
|
||||
*
|
||||
* fmt, ...: same as ui_status_update()
|
||||
*/
|
||||
|
||||
void ui_indeterminate_begin(Options *op, const char *fmt, ...)
|
||||
{
|
||||
IndeterminateData *id = op->ui.indeterminate_data;
|
||||
static struct indeterminate_args args;
|
||||
char *msg;
|
||||
|
||||
if (!op->silent && fmt != NULL) {
|
||||
NV_VSNPRINTF(msg, fmt);
|
||||
args.op = op;
|
||||
args.msg = msg;
|
||||
|
||||
indeterminate_begin(id, indeterminate_worker, &args);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ui_indeterminate_end(): terminate an indeterminate status indicator
|
||||
*/
|
||||
|
||||
void ui_indeterminate_end(Options *op)
|
||||
{
|
||||
indeterminate_end(op->ui.indeterminate_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* ui_status_end(): finish the progress indicator created with ui_status_begin()
|
||||
*/
|
||||
void ui_status_end(Options *op, const char *fmt, ...)
|
||||
{
|
||||
char *msg;
|
||||
@@ -502,6 +577,8 @@ void ui_status_end(Options *op, const char *fmt, ...)
|
||||
if (!op->silent) __ui->status_end(op, msg);
|
||||
log_printf(op, NV_BULLET_STR, "%s", msg);
|
||||
free(msg);
|
||||
|
||||
op->ui.status_active = FALSE;
|
||||
}
|
||||
|
||||
|
||||
@@ -516,6 +593,8 @@ void ui_close (Options *op)
|
||||
|
||||
__ui = NULL;
|
||||
|
||||
indeterminate_destroy(op->ui.indeterminate_data);
|
||||
op->ui.indeterminate_data = NULL;
|
||||
} /* ui_close() */
|
||||
|
||||
|
||||
|
@@ -50,6 +50,8 @@ int ui_paged_prompt (Options *, const char *, const char *,
|
||||
const char *, const char * const *, int, int);
|
||||
void ui_status_begin (Options*, const char*, const char*, ...) NV_ATTRIBUTE_PRINTF(3, 4);
|
||||
void ui_status_update (Options*, const float, const char*, ...) NV_ATTRIBUTE_PRINTF(3, 4);
|
||||
void ui_indeterminate_begin (Options*, const char*, ...) NV_ATTRIBUTE_PRINTF(2, 3);
|
||||
void ui_indeterminate_end (Options*);
|
||||
void ui_status_end (Options*, const char*, ...) NV_ATTRIBUTE_PRINTF(2, 3);
|
||||
void ui_close (Options*);
|
||||
|
||||
|
15
utils.mk
15
utils.mk
@@ -565,11 +565,26 @@ endef
|
||||
# $(1): Path to the file to convert
|
||||
##############################################################################
|
||||
|
||||
LD_TARGET_EMULATION_FLAG =
|
||||
LD_TARGET_EMULATION_FLAG_Linux_x86 = elf_i386
|
||||
LD_TARGET_EMULATION_FLAG_Linux_x86_64 = elf_x86_64
|
||||
LD_TARGET_EMULATION_FLAG_Linux_aarch64 = aarch64elf
|
||||
LD_TARGET_EMULATION_FLAG_Linux_ppc64le = elf64lppc
|
||||
LD_TARGET_EMULATION_FLAG_SunOS_x86 = elf_i386_sol2
|
||||
LD_TARGET_EMULATION_FLAG_SunOS_x86_64 = elf_x86_64_sol2
|
||||
LD_TARGET_EMULATION_FLAG_FreeBSD_x86 = elf_i386_fbsd
|
||||
LD_TARGET_EMULATION_FLAG_FreeBSD_x86_64 = elf_x86_64_fbsd
|
||||
|
||||
ifdef LD_TARGET_EMULATION_FLAG_$(TARGET_OS)_$(TARGET_ARCH)
|
||||
LD_TARGET_EMULATION_FLAG = -m $(LD_TARGET_EMULATION_FLAG_$(TARGET_OS)_$(TARGET_ARCH))
|
||||
endif
|
||||
|
||||
define READ_ONLY_OBJECT_FROM_FILE_RULE
|
||||
$$(OUTPUTDIR)/$$(notdir $(1)).o: $(1)
|
||||
$(at_if_quiet)$$(MKDIR) $$(OUTPUTDIR)
|
||||
$(at_if_quiet)cd $$(dir $(1)); \
|
||||
$$(call quiet_cmd_no_at,LD) -r -z noexecstack --format=binary \
|
||||
$$(LD_TARGET_EMULATION_FLAG) \
|
||||
$$(notdir $(1)) -o $$(OUTPUTDIR_ABSOLUTE)/$$(notdir $$@)
|
||||
$$(call quiet_cmd,OBJCOPY) \
|
||||
--rename-section .data=.rodata,contents,alloc,load,data,readonly \
|
||||
|
@@ -1,4 +1,4 @@
|
||||
NVIDIA_VERSION = 535.113.01
|
||||
NVIDIA_VERSION = 545.23.06
|
||||
|
||||
# This file.
|
||||
VERSION_MK_FILE := $(lastword $(MAKEFILE_LIST))
|
||||
|
Reference in New Issue
Block a user