From 2fdb443bc82f2a554f29b5b1482f2a27a7dcc3d1 Mon Sep 17 00:00:00 2001 From: Aaron Plattner Date: Wed, 13 Feb 2008 10:22:35 -0800 Subject: 1.0-7182 --- DRIVER_VERSION | 1 + Makefile | 45 +++- backup.c | 39 ++-- command-list.c | 308 ++++++++++++++++++-------- command-list.h | 2 - files.c | 557 +++++++++++++++++++++++++++++++++++++---------- files.h | 5 + gen-manpage-opts.c | 123 +++++++++++ install-from-cwd.c | 221 +++++++++++-------- kernel.c | 292 ++++++++++++++----------- kernel.h | 2 +- misc.c | 517 +++++++++++++++++++++++++++++++++++++++---- misc.h | 19 +- mkprecompiled.c | 12 +- ncurses-ui.c | 140 ++++++++---- nvidia-installer.1.m4 | 115 ++++++++++ nvidia-installer.c | 591 ++++++++++++++------------------------------------ nvidia-installer.h | 148 ++++++++----- option_table.h | 352 ++++++++++++++++++++++++++++++ precompiled.c | 12 +- sanity.c | 184 ---------------- snarf-ftp.c | 6 +- snarf-http.c | 50 +++-- snarf.c | 2 +- update.c | 14 +- user-interface.c | 4 +- 26 files changed, 2516 insertions(+), 1245 deletions(-) create mode 100644 DRIVER_VERSION create mode 100644 gen-manpage-opts.c create mode 100644 nvidia-installer.1.m4 create mode 100644 option_table.h diff --git a/DRIVER_VERSION b/DRIVER_VERSION new file mode 100644 index 0000000..30bc213 --- /dev/null +++ b/DRIVER_VERSION @@ -0,0 +1 @@ +1.0-7182 diff --git a/Makefile b/Makefile index 7e8224a..8182d8b 100644 --- a/Makefile +++ b/Makefile @@ -68,6 +68,7 @@ endif exec_prefix = $(prefix) bindir = $(exec_prefix)/bin +mandir = $(exec_prefix)/share/man/man1 # Can be overwitten by users for cross-compiling # get the os and architecture @@ -115,6 +116,10 @@ GEN_UI_ARRAY = ./gen-ui-array CONFIG_H = config.h STAMP_C = g_stamp.c +MANPAGE = nvidia-installer.1 + +DRIVER_VERSION=$(shell cat DRIVER_VERSION) + # Setup some architecture specific build options ifeq ($(INSTALLER_OS)-$(INSTALLER_ARCH), Linux-x86_64) TLS_MODEL=initial-exec @@ -165,9 +170,9 @@ MKPRECOMPILED_OBJS = $(MKPRECOMPILED_SRC:.c=.o) default: all -all: $(NVIDIA_INSTALLER) $(MKPRECOMPILED) +all: $(NVIDIA_INSTALLER) $(MKPRECOMPILED) $(MANPAGE) -install: NVIDIA_INSTALLER_install MKPRECOMPILED_install +install: NVIDIA_INSTALLER_install MKPRECOMPILED_install MANPAGE_install NVIDIA_INSTALLER_install: $(NVIDIA_INSTALLER) $(STRIP) $< @@ -176,6 +181,11 @@ NVIDIA_INSTALLER_install: $(NVIDIA_INSTALLER) MKPRECOMPILED_install: $(MKPRECOMPILED) $(INSTALL) $< $(bindir)/$< +MANPAGE_install: $(MANPAGE) + mkdir -p $(mandir) + $(INSTALL) -m 644 $< $(mandir)/$< + gzip -9f $(mandir)/$(MANPAGE) + $(MKPRECOMPILED): $(CONFIG_H) $(MKPRECOMPILED_OBJS) $(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(MKPRECOMPILED_OBJS) -o $@ @@ -242,7 +252,8 @@ clean clobber: rm -rf $(NVIDIA_INSTALLER) $(MKPRECOMPILED) \ $(NCURSES_UI) $(NCURSES_UI_C) \ $(TLS_TEST_C) $(TLS_TEST_DSO_C) $(RTLD_TEST_C) $(COMPAT_32_SRC) \ - $(GEN_UI_ARRAY) $(CONFIG_H) $(STAMP_C) *.o *~ *.d + $(GEN_UI_ARRAY) $(CONFIG_H) $(STAMP_C) *.o *~ *.d \ + $(MANPAGE) gen-manpage-opts options.1.inc # rule to rebuild tls_test and tls_test_dso; a precompiled tls_test # and tls_test_dso is distributed with nvidia_installer because they @@ -279,4 +290,32 @@ rtld_test: rtld_test.c print_version: @ echo $(NVIDIA_INSTALLER_VERSION) + +### Documentation + +AUTO_TEXT = ".\\\" WARNING: THIS FILE IS AUTO-GENERATED! Edit $< instead." + +doc: $(MANPAGE) + +gen-manpage-opts.o: gen-manpage-opts.c $(CONFIG_H) + $(HOST_CC) $(ALL_CFLAGS) -c $< + +gen-manpage-opts: gen-manpage-opts.o + $(HOST_CC) $(CFLAGS) $^ $(ALL_LDFLAGS) -o $@ + +-include gen-manpage-opts.d + +options.1.inc: gen-manpage-opts + ./$< > $@ + +nvidia-installer.1: nvidia-installer.1.m4 options.1.inc DRIVER_VERSION + m4 -D__HEADER__=$(AUTO_TEXT) \ + -D__VERSION__=$(NVIDIA_INSTALLER_VERSION) \ + -D__INSTALLER_OS__="$(INSTALLER_OS)" \ + -D__INSTALLER_ARCH__="$(INSTALLER_ARCH)" \ + -D__DRIVER_VERSION__="$(DRIVER_VERSION)" \ + $< > $@ + +### + -include $(SRC:.c=.d) diff --git a/backup.c b/backup.c index 899cd74..b061852 100644 --- a/backup.c +++ b/backup.c @@ -515,7 +515,7 @@ static int do_uninstall(Options *op) existing_installation_is_borked, op->log_file_name); } else { - ui_warn(op, existing_installation_is_borked); + ui_warn(op, "%s", existing_installation_is_borked); } } @@ -659,7 +659,7 @@ static BackupInfo *read_backup_log_file(Options *op) { struct stat stat_buf; char *buf, *c, *line, *filename; - int fd, num, line_num = 0; + int fd, num, length, line_num = 0; float percent; BackupLogEntry *e; @@ -698,7 +698,9 @@ static BackupInfo *read_backup_log_file(Options *op) /* map the file */ - buf = mmap(0, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0); + length = stat_buf.st_size; + + buf = mmap(0, length, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0); if (!buf) { ui_error(op, "Unable to mmap file '%s' (%s).", strerror(errno)); return NULL; @@ -708,13 +710,13 @@ static BackupInfo *read_backup_log_file(Options *op) b = nvalloc(sizeof(BackupInfo)); - b->version = get_next_line(buf, &c); + b->version = get_next_line(buf, &c, buf, length); if (!b->version || !c) goto parse_error; percent = (float) (c - buf) / (float) stat_buf.st_size; ui_status_update(op, percent, NULL); - b->description = get_next_line(c, &c); + b->description = get_next_line(c, &c, buf, length); if (!b->description || !c) goto parse_error; b->n = 0; @@ -728,7 +730,7 @@ static BackupInfo *read_backup_log_file(Options *op) /* read and parse the next line */ - line = get_next_line(c, &c); + line = get_next_line(c, &c, buf, length); if (!line) break; if (!parse_first_line(line, &num, &filename)) goto parse_error; @@ -749,7 +751,8 @@ static BackupInfo *read_backup_log_file(Options *op) switch(e->num) { case INSTALLED_FILE: - if ((line = get_next_line(c, &c)) == NULL) goto parse_error; + line = get_next_line(c, &c, buf, length); + if (line == NULL) goto parse_error; line_num++; if (!parse_crc(line, &e->crc)) goto parse_error; @@ -758,7 +761,8 @@ static BackupInfo *read_backup_log_file(Options *op) break; case INSTALLED_SYMLINK: - if ((line = get_next_line(c, &c)) == NULL) goto parse_error; + line = get_next_line(c, &c, buf, length); + if (line == NULL) goto parse_error; line_num++; e->target = line; @@ -766,12 +770,14 @@ static BackupInfo *read_backup_log_file(Options *op) break; case BACKED_UP_SYMLINK: - if ((line = get_next_line(c, &c)) == NULL) goto parse_error; + line = get_next_line(c, &c, buf, length); + if (line == NULL) goto parse_error; line_num++; e->target = line; - if ((line = get_next_line(c, &c)) == NULL) goto parse_error; + line = get_next_line(c, &c, buf, length); + if (line == NULL) goto parse_error; line_num++; if (!parse_mode_uid_gid(line, &e->mode, &e->uid, &e->gid)) @@ -783,7 +789,8 @@ static BackupInfo *read_backup_log_file(Options *op) default: if (num < BACKED_UP_FILE_NUM) goto parse_error; - if ((line = get_next_line(c, &c)) == NULL) goto parse_error; + line = get_next_line(c, &c, buf, length); + if (line == NULL) goto parse_error; line_num++; if (!parse_crc_mode_uid_gid(line, &e->crc, &e->mode, @@ -980,23 +987,25 @@ char *get_installed_driver_version_and_descr(Options *op, int *major, { struct stat stat_buf; char *c, *version = NULL, *descr = NULL, *buf = NULL; - int fd = -1; + int length, fd = -1; if ((fd = open(BACKUP_LOG, O_RDONLY)) == -1) goto done; if (fstat(fd, &stat_buf) == -1) goto done; /* map the file */ + + length = stat_buf.st_size; - buf = mmap(0, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0); + buf = mmap(0, length, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0); if (!buf) goto done; - version = get_next_line(buf, &c); + version = get_next_line(buf, &c, buf, length); if (!version) goto done; if (!nvid_version(version, major, minor, patch)) goto done; - descr = get_next_line(c, NULL); + descr = get_next_line(c, NULL, buf, length); done: if (version) free(version); diff --git a/command-list.c b/command-list.c index fc721d6..87c5a94 100644 --- a/command-list.c +++ b/command-list.c @@ -47,14 +47,26 @@ #include "kernel.h" +static void find_conflicting_xfree86_libraries(Options *, + const char *, + FileList *); + +static void find_conflicting_xfree86_libraries_fullpath(Options *op, + const char *, + FileList *l); + +static void find_conflicting_opengl_libraries(Options *, + const char *, + FileList *); -static void find_existing_files(Package *p, FileList *l, unsigned int); static void find_conflicting_kernel_modules(Options *op, - Package *p, FileList *l); + Package *p, + FileList *l); + +static void find_existing_files(Package *p, FileList *l, unsigned int); static void add_command (CommandList *c, int cmd, ...); -static void find_matches (const char*, const char*, FileList*, const int); static void add_file_to_list(const char*, const char*, FileList*); static void append_to_rpm_file_list(Options *op, Command *c); @@ -91,13 +103,30 @@ CommandList *build_command_list(Options *op, Package *p) if (!op->kernel_module_only) { - find_conflicting_xfree86_libraries - (op, DEFAULT_XFREE86_INSTALLATION_PREFIX, l); + if (!is_symbolic_link_to(DEFAULT_XFREE86_INSTALLATION_PREFIX, + DEFAULT_OPENGL_INSTALLATION_PREFIX) + && !is_symbolic_link_to(DEFAULT_XFREE86_INSTALLATION_PREFIX, + op->opengl_prefix)) { + find_conflicting_xfree86_libraries + (op, DEFAULT_XFREE86_INSTALLATION_PREFIX, l); + } if (strcmp(DEFAULT_XFREE86_INSTALLATION_PREFIX, - op->xfree86_prefix) != 0) - find_conflicting_xfree86_libraries(op, op->xfree86_prefix, l); - + op->xfree86_prefix) != 0) { + if (!is_symbolic_link_to(op->xfree86_prefix, + DEFAULT_OPENGL_INSTALLATION_PREFIX) + && !is_symbolic_link_to(op->xfree86_prefix, op->opengl_prefix)) + find_conflicting_xfree86_libraries(op, op->xfree86_prefix, l); + } + + /* + * Note that searching op->x_module_path may produce + * duplicates of conflicting files we found above; this is OK + * because condense_file_list() will remove any duplicates. + */ + + find_conflicting_xfree86_libraries_fullpath(op, op->x_module_path, l); + find_conflicting_opengl_libraries (op, DEFAULT_OPENGL_INSTALLATION_PREFIX, l); @@ -117,11 +146,24 @@ CommandList *build_command_list(Options *op, Package *p) find_conflicting_opengl_libraries(op, prefix, l); nvfree(prefix); } + + prefix = nvstrcat(op->compat32_prefix, + DEFAULT_XFREE86_INSTALLATION_PREFIX, NULL); + find_conflicting_opengl_libraries(op, prefix, l); + nvfree(prefix); + + if (strcmp(DEFAULT_XFREE86_INSTALLATION_PREFIX, + op->xfree86_prefix) != 0) { + prefix = nvstrcat(op->compat32_prefix, op->xfree86_prefix, NULL); + find_conflicting_opengl_libraries(op, prefix, l); + nvfree(prefix); + } } #endif /* NV_X86_64 */ } - find_conflicting_kernel_modules(op, p, l); + if (!op->no_kernel_module) + find_conflicting_kernel_modules(op, p, l); /* * find any existing files that clash with what we're going to @@ -167,14 +209,23 @@ CommandList *build_command_list(Options *op, Package *p) } /* - * delete the temporary libGL.la file generated based on - * the template earlier. + * delete the temporary libGL.la and .desktop files generated + * based on templates earlier. */ - if (p->entries[i].flags & FILE_TYPE_LIBGL_LA) { + if ((p->entries[i].flags & FILE_TYPE_LIBGL_LA) || + (p->entries[i].flags & FILE_TYPE_DOT_DESKTOP)) { add_command(c, DELETE_CMD, p->entries[i].file); } + + if (op->selinux_enabled && + (p->entries[i].flags & FILE_TYPE_SHARED_LIB)) { + tmp = nvstrcat(op->utils[CHCON], " -t shlib_t ", p->entries[i].dst, + NULL); + add_command(c, RUN_CMD, tmp); + nvfree(tmp); + } } @@ -395,19 +446,25 @@ int execute_command_list(Options *op, CommandList *c, typedef struct { const char *name; int len; -} ConflictingLibInfo; +} ConflictingFileInfo; + +static void find_conflicting_files(Options *op, + char *path, + ConflictingFileInfo *files, + FileList *l); static void find_conflicting_libraries(Options *op, const char *prefix, - ConflictingLibInfo *libs, + ConflictingFileInfo *libs, FileList *l); -static ConflictingLibInfo __xfree86_libs[] = { +static ConflictingFileInfo __xfree86_libs[] = { { "libGLcore.", 10 /* strlen("libGLcore.") */ }, { "libGL.", 6 /* strlen("libGL.") */ }, { "libGLwrapper.", 13 /* strlen("libGLwrapper.") */ }, { "libglx.", 7 /* strlen("libglx.") */ }, - { "libXvMCNVIDIA", 14 /* strlen("libXvMCNVIDIA") */ }, + { "libXvMCNVIDIA", 13 /* strlen("libXvMCNVIDIA") */ }, + { "libnvidia-cfg.", 14 /* strlen("libnvidia-cfg.") */ }, { NULL, 0 } }; @@ -417,15 +474,35 @@ static ConflictingLibInfo __xfree86_libs[] = { * libdirs. */ -void find_conflicting_xfree86_libraries(Options *op, - const char *xprefix, FileList *l) +static void find_conflicting_xfree86_libraries(Options *op, + const char *xprefix, + FileList *l) { find_conflicting_libraries(op, xprefix, __xfree86_libs, l); } /* find_conflicting_xfree86_libraries() */ -static ConflictingLibInfo __opengl_libs[] = { + +/* + * find_conflicting_xfree86_libraries_fullpath() - same as + * find_conflicting_xfree86_libraries, but bypasses the + * find_conflicting_libraries step, which appends "lib", "lib64", and + * "lib32" to the path name. Use this when you have the fullpath that + * you want searched. + */ + +static void find_conflicting_xfree86_libraries_fullpath(Options *op, + const char *path, + FileList *l) +{ + find_conflicting_files(op, (char *) path, __xfree86_libs, l); + +} /* find_conflicting_xfree86_libraries_fullpath() */ + + + +static ConflictingFileInfo __opengl_libs[] = { { "libGLcore.", 10 /* strlen("libGLcore.") */ }, { "libGL.", 6 /* strlen("libGL.") */ }, { "libnvidia-tls.", 14 /* strlen("libnvidia-tls.") */ }, @@ -439,8 +516,9 @@ static ConflictingLibInfo __opengl_libs[] = { * libdirs. */ -void find_conflicting_opengl_libraries(Options *op, - const char *glprefix, FileList *l) +static void find_conflicting_opengl_libraries(Options *op, + const char *glprefix, + FileList *l) { find_conflicting_libraries(op, glprefix, __opengl_libs, l); @@ -451,41 +529,44 @@ void find_conflicting_opengl_libraries(Options *op, /* * find_conflicting_kernel_modules() - search for conflicting kernel * modules under the kernel module installation prefix. - * - * XXX rather than use a fixed list of prefixes, maybe we should scan for the - * kernel module name anywhere under /lib/modules/`uname -r`/ ? */ static void find_conflicting_kernel_modules(Options *op, Package *p, FileList *l) { int i, n = 0; - char *prefixes[5]; + ConflictingFileInfo files[2]; + char *paths[3]; char *tmp = get_kernel_name(op); - prefixes[0] = op->kernel_module_installation_path; + files[1].name = NULL; + files[1].len = 0; + paths[0] = op->kernel_module_installation_path; if (tmp) { - prefixes[1] = nvstrcat("/lib/modules/", tmp, "/kernel/drivers/video", NULL); - prefixes[2] = nvstrcat("/lib/modules/", tmp, "/kernel/drivers/char", NULL); - prefixes[3] = nvstrcat("/lib/modules/", tmp, "/video", NULL); - prefixes[4] = NULL; + paths[1] = nvstrcat("/lib/modules/", tmp, NULL); + paths[2] = NULL; } else { - prefixes[1] = NULL; + paths[1] = NULL; } - /* look for all the conflicting module names in all the possible prefixes */ - - for (i = 0; prefixes[i]; i++) { + for (i = 0; paths[i]; i++) { for (n = 0; p->bad_module_filenames[n]; n++) { - find_matches(prefixes[i], p->bad_module_filenames[n], l, TRUE); + /* + * Recursively search for this conflicting kernel module + * relative to the current prefix. + */ + files[0].name = p->bad_module_filenames[n]; + files[0].len = strlen(files[0].name); + + find_conflicting_files(op, paths[i], files, l); } } - /* free any prefixes we nvstrcat()ed above */ + /* free any paths we nvstrcat()'d above */ - for (i = 1; prefixes[i]; i++) { - nvfree(prefixes[i]); + for (i = 1; paths[i]; i++) { + nvfree(paths[i]); } } /* find_conflicting_kernel_modules() */ @@ -516,24 +597,23 @@ static void find_existing_files(Package *p, FileList *l, unsigned int flag) /* - * find_conflicting_libraries() - search for any conflicting - * libraries in all relevant libdirs within the hierarchy under + * find_conflicting_files() - search for any conflicting + * files in all the specified paths within the hierarchy under * the given prefix. */ -static void find_conflicting_libraries(Options *op, - const char *prefix, - ConflictingLibInfo *libs, - FileList *l) +static void find_conflicting_files(Options *op, + char *path, + ConflictingFileInfo *files, + FileList *l) { int i; - char *paths[3]; + char *paths[2]; FTS *fts; FTSENT *ent; - paths[0] = nvstrcat(prefix, "/", "lib", NULL); - paths[1] = nvstrcat(prefix, "/", "lib64", NULL); - paths[2] = NULL; + paths[0] = path; /* search root */ + paths[1] = NULL; fts = fts_open(paths, FTS_LOGICAL | FTS_NOSTAT, NULL); if (!fts) return; @@ -542,8 +622,8 @@ static void find_conflicting_libraries(Options *op, switch (ent->fts_info) { case FTS_F: case FTS_SLNONE: - for (i = 0; libs[i].name; i++) { - if (!strncmp(ent->fts_name, libs[i].name, libs[i].len)) + for (i = 0; files[i].name; i++) { + if (!strncmp(ent->fts_name, files[i].name, files[i].len)) add_file_to_list(NULL, ent->fts_path, l); } break; @@ -568,7 +648,54 @@ static void find_conflicting_libraries(Options *op, fts_close(fts); - for (i = 0; paths[i]; i++) +} /* find_conflicting_files() */ + + + + +/* + * find_conflicting_libraries() - search for any conflicting + * libraries in all relevant libdirs within the hierarchy under + * the given prefix. + */ + +static void find_conflicting_libraries(Options *op, + const char *prefix, + ConflictingFileInfo *files, + FileList *l) +{ + int i, j; + char *paths[4]; + + paths[0] = nvstrcat(prefix, "/", "lib", NULL); + paths[1] = nvstrcat(prefix, "/", "lib64", NULL); + paths[2] = nvstrcat(prefix, "/", "lib32", NULL); + paths[3] = NULL; + + for (i = 0; paths[i]; i++) { + for (j = 0; (j < 3) && paths[i]; j++) { + /* + * XXX Check if any one of the 'paths' entries really + * is a symbolic link pointing to one of the other + * entries. The logic could be made smarter, since it's + * unlikely that ../lib32 would be a symbolic link to + * ../lib64 or vice versa. + */ + if (!paths[j] || (i == j)) continue; + + if (is_symbolic_link_to(paths[i], paths[j])) { + ui_expert(op, "The conflicting library search path " + "'%s' is a symbolic link to the library " + "search path '%s'; skipping '%s'.", + paths[i], paths[j], paths[i]); + free(paths[i]); paths[i] = NULL; + } + } + + if (paths[i]) find_conflicting_files(op, paths[i], files, l); + } + + for (i = 0; i < 3; i++) nvfree(paths[i]); } /* find_conflicting_libraries() */ @@ -585,10 +712,40 @@ void condense_file_list(FileList *l) char **s = NULL; int n = 0, i, j, match; + struct stat stat_buf, *stat_bufs; + + /* allocate enough space in our temporary 'stat' array */ + + if (l->num) { + stat_bufs = nvalloc(sizeof(struct stat) * l->num); + } else { + stat_bufs = NULL; + } + + /* + * walk through our original (uncondensed) list of files and move + * unique files to a new (condensed) list. For each file in the + * original list, get the filesystem information for the file, and + * then compare that to the filesystem information for all the + * files in the new list. If the file from the original list does + * not match any file in the new list, add it to the new list. + */ + for (i = 0; i < l->num; i++) { match = FALSE; + + if (lstat(l->filename[i], &stat_buf) == -1) + continue; + for (j = 0; j < n; j++) { - if (strcmp(l->filename[i], s[j]) == 0) { + + /* + * determine if the two files are the same by comparing + * device and inode + */ + + if ((stat_buf.st_dev == stat_bufs[j].st_dev) && + (stat_buf.st_ino == stat_bufs[j].st_ino)) { match = TRUE; break; } @@ -597,10 +754,13 @@ void condense_file_list(FileList *l) if (!match) { s = (char **) nvrealloc(s, sizeof(char *) * (n + 1)); s[n] = nvstrdup(l->filename[i]); + stat_bufs[n] = stat_buf; n++; } } + if (stat_bufs) nvfree((void *)stat_bufs); + for (i = 0; i < l->num; i++) free(l->filename[i]); free(l->filename); @@ -669,50 +829,6 @@ static void add_command(CommandList *c, int cmd, ...) -/* - * find_matches() - given a directory, a filename, and an existing - * FileList data structure, open the specified directory, and look for - * any entries that match the filename. - * - * If the parameter 'exact' is TRUE, then the filenames must match - * exactly. If 'exact' is FALSE, then only the beginning of the - * directory entry name must match the filename in question. - * - * This could alternatively be implemented using glob(3). - */ - -static void find_matches(const char *directory, const char *filename, - FileList *l, const int exact) -{ - struct stat stat_buf; - struct dirent *ent; - int len; - DIR *dir; - - if (lstat(directory, &stat_buf) == -1) return; - if (S_ISDIR(stat_buf.st_mode) == 0) return; - if ((dir = opendir(directory)) == NULL) return; - - len = strlen(filename); - - while ((ent = readdir(dir)) != NULL) { - if (exact) { - if (strcmp(ent->d_name, filename) == 0) { - add_file_to_list(directory, ent->d_name, l); - } - } else { - if (strncmp(ent->d_name, filename, len) == 0) { - add_file_to_list(directory, ent->d_name, l); - } - } - } - - closedir (dir); - -} /* find_matches() */ - - - /* * add_file_to_list() - concatenate the given directory and filename, * appending to the FileList structure. If the 'directory' parameter diff --git a/command-list.h b/command-list.h index ca85a23..6b2d225 100644 --- a/command-list.h +++ b/command-list.h @@ -83,8 +83,6 @@ CommandList *build_command_list(Options*, Package *); void free_command_list(Options*, CommandList*); int execute_command_list(Options*, CommandList*, const char*, const char*); -void find_conflicting_xfree86_libraries(Options*,const char*, FileList*); -void find_conflicting_opengl_libraries(Options*, const char*, FileList*); void condense_file_list(FileList *l); #endif /* __NVIDIA_INSTALLER_COMMAND_LIST_H__ */ diff --git a/files.c b/files.c index ea6c028..5d0b91e 100644 --- a/files.c +++ b/files.c @@ -47,6 +47,10 @@ #include "misc.h" #include "precompiled.h" + +static int get_x_module_path(Options *op); + + /* * remove_directory() - recursively delete a direcotry (`rm -rf`) */ @@ -478,11 +482,66 @@ void select_tls_class(Options *op, Package *p) int set_destinations(Options *op, Package *p) { - char *prefix, *path, *name; + char *prefix, *path, *name, *s; + char *xdg_data_dir; int i; + s = NULL; for (i = 0; i < p->num_entries; i++) { +#if defined(NV_X86_64) + if (p->entries[i].flags & FILE_TYPE_HAVE_PATH) { + if ((op->distro == DEBIAN || op->distro == UBUNTU) && + (s = strstr(p->entries[i].path, "lib64"))) { + /* + * XXX Debian GNU/Linux for Linux/x86-64 doesn't follow + * the "lib64" convention used by other distributors. + * The 64-bit libraries are installed in ../lib. Ubuntu + * Linux inherited this layout. + */ + + /* + * The default 64-bit destination path is ../lib64. + * Get the length of the string following "lib64", then + * move this remainder over the "64". + */ + int j, len = strlen(s+5); + for (j = 0; j <= len; j++) s[j+3] = s[j+5]; + + } else if (((op->distro == UBUNTU) || + (op->distro == GENTOO)) && + (p->entries[i].flags & FILE_CLASS_COMPAT32) && + (s = strstr(p->entries[i].path, "lib"))) { + /* + * XXX Ubuntu for Linux/x86-64 doesn't follow the "lib" + * convention used by other distributors; the 32-bit + * libraries are installed in ../lib32, instead. Patch + * up the destination path accordingly. + * + * Sadly, the same thing is also true for Gentoo Linux. + */ + + /* + * The default 32-bit destination path is ../lib. + * If this entry's path ends with "lib", go ahead and + * replace it with ../lib32, else replace the "lib" + * in the path with "lib32". + */ + if (*(s+3) == '\0') { + path = p->entries[i].path; + p->entries[i].path = nvstrcat(path, "32", NULL); + free(path); + } else if ((s+4) != NULL) { + *(s+3) = '\0'; + path = p->entries[i].path; + p->entries[i].path = nvstrcat(path, "32/", s+4, NULL); + free(path); + } else + p->entries[i].dst = NULL; + } + } +#endif /* NV_X86_64 */ + switch (p->entries[i].flags & FILE_TYPE_MASK) { case FILE_TYPE_KERNEL_MODULE_CMD: @@ -499,12 +558,20 @@ int set_destinations(Options *op, Package *p) path = p->entries[i].path; break; - case FILE_TYPE_XFREE86_LIB: - case FILE_TYPE_XFREE86_SYMLINK: + case FILE_TYPE_XLIB_SHARED_LIB: + case FILE_TYPE_XLIB_STATIC_LIB: + case FILE_TYPE_XLIB_SYMLINK: prefix = op->xfree86_prefix; path = p->entries[i].path; break; + case FILE_TYPE_XMODULE_SHARED_LIB: + case FILE_TYPE_XMODULE_STATIC_LIB: + case FILE_TYPE_XMODULE_SYMLINK: + prefix = op->x_module_path; + path = p->entries[i].path; + break; + case FILE_TYPE_TLS_LIB: case FILE_TYPE_TLS_SYMLINK: prefix = op->opengl_prefix; @@ -543,6 +610,24 @@ int set_destinations(Options *op, Package *p) path = UTILITY_BINARY_DST_PATH; break; + case FILE_TYPE_DOT_DESKTOP: + /* + * If XDG_DATA_DIRS is set, then derive the installation path + * from the first entry; complies with: + * http://www.freedesktop.org/Standards/basedir-spec + */ + xdg_data_dir = getenv("XDG_DATA_DIRS"); + if (xdg_data_dir) xdg_data_dir = nvstrdup(strtok(xdg_data_dir, ":")); + + if (xdg_data_dir != NULL) { + prefix = xdg_data_dir; + path = nvstrdup("applications"); + } else { + prefix = op->opengl_prefix; + path = DOT_DESKTOP_DST_PATH; + } + break; + case FILE_TYPE_KERNEL_MODULE: /* @@ -600,7 +685,7 @@ int set_destinations(Options *op, Package *p) int get_license_acceptance(Options *op) { struct stat buf; - char *text; + char *text, *tmp; int fd; /* trivial accept if the user accepted on the command line */ @@ -618,8 +703,18 @@ int get_license_acceptance(Options *op) MAP_FILE|MAP_SHARED, fd, 0x0)) == (char *) -1) goto failed; - if (!ui_display_license(op, text)) { + /* + * the mmap'ed license file may not be NULL terminated, so copy it + * into a temporary buffer and explicity NULL terminate the string + */ + + tmp = nvalloc(buf.st_size + 1); + memcpy(tmp, text, buf.st_size); + tmp[buf.st_size] = '\0'; + + if (!ui_display_license(op, tmp)) { ui_message(op, "License not accepted. Aborting installation."); + nvfree(tmp); munmap(text, buf.st_size); close(fd); return FALSE; @@ -627,6 +722,7 @@ int get_license_acceptance(Options *op) ui_log(op, "License accepted."); + nvfree(tmp); munmap(text, buf.st_size); close(fd); @@ -665,6 +761,29 @@ int get_prefixes (Options *op) remove_trailing_slashes(op->xfree86_prefix); ui_expert(op, "X installation prefix is: '%s'", op->xfree86_prefix); + + /* + * assign the X module path; this must be done after + * op->xfree86_prefix is assigned + */ + + if (!get_x_module_path(op)) { + return FALSE; + } + + if (op->expert) { + ret = ui_get_input(op, op->x_module_path, + "X module installation path (only under " + "rare circumstances should this be changed " + "from the default)"); + if (ret && ret[0]) { + op->x_module_path = ret; + if (!confirm_path(op, op->x_module_path)) return FALSE; + } + } + + remove_trailing_slashes(op->x_module_path); + ui_expert(op, "X module installation path is: '%s'", op->x_module_path); if (op->expert) { ret = ui_get_input(op, op->opengl_prefix, @@ -1408,6 +1527,157 @@ static char *nv_strreplace(char *src, char *orig, char *replace) +/* + * process_template_file() - copy the specified template file to + * a temporary file, replacing specified tokens with specified + * replacement strings. Return the temporary file's path to the + * caller or NULL, if an error occurs. + */ + +char *process_template_file(Options *op, PackageEntry *pe, + char **tokens, char **replacements) +{ + int failed, src_fd, dst_fd, len; + struct stat stat_buf; + char *src, *dst, *tmp, *tmp0, *tmpfile = NULL; + char *token, *replacement; + + failed = FALSE; + src_fd = dst_fd = -1; + tmp = tmp0 = src = dst = tmpfile = NULL; + len = 0; + + /* open the file */ + + if ((src_fd = open(pe->file, O_RDONLY)) == -1) { + ui_error(op, "Unable to open '%s' for copying (%s)", + pe->file, strerror(errno)); + return NULL; + } + + /* get the size of the file */ + + if (fstat(src_fd, &stat_buf) == -1) { + ui_error(op, "Unable to determine size of '%s' (%s)", + pe->file, strerror(errno)); + failed = TRUE; goto done; + } + + /* mmap the file */ + + if ((src = mmap(0, stat_buf.st_size, PROT_READ, + MAP_FILE|MAP_SHARED, src_fd, 0)) == MAP_FAILED) { + ui_error (op, "Unable to map source file '%s' for " + "copying (%s)", pe->file, strerror(errno)); + src = NULL; + failed = TRUE; goto done; + } + + if (!src) { + ui_log(op, "%s is empty; skipping.", pe->file); + failed = TRUE; goto done; + } + + /* + * allocate a string to hold the contents of the mmap'ed file, + * plus explicit NULL termination + */ + + tmp = nvalloc(stat_buf.st_size + 1); + memcpy(tmp, src, stat_buf.st_size); + tmp[stat_buf.st_size] = '\0'; + + /* setup to walk the tokens and replacements arrays */ + + token = *tokens; + replacement = *replacements; + + while (token != NULL && replacement != NULL) { + /* + * Replace any occurances of 'token' with 'replacement' in + * the source string and free the source + */ + tmp0 = nv_strreplace(tmp, token, replacement); + nvfree(tmp); + tmp = tmp0; + token = *(++tokens); + replacement = *(++replacements); + } + + /* create a temporary file to store the processed template file */ + + tmpfile = nvstrcat(op->tmpdir, "/template-XXXXXX", NULL); + if ((dst_fd = mkstemp(tmpfile)) == -1) { + ui_error(op, "Unable to create temporary file (%s)", + strerror(errno)); + failed = TRUE; goto done; + } + + /* set the size of the new file */ + + len = strlen(tmp); + + if (lseek(dst_fd, len - 1, SEEK_SET) == -1) { + ui_error(op, "Unable to set file size for '%s' (%s)", + tmpfile, strerror(errno)); + failed = TRUE; goto done; + } + if (write(dst_fd, "", 1) != 1) { + ui_error(op, "Unable to write file size for '%s' (%s)", + tmpfile, strerror(errno)); + failed = TRUE; goto done; + } + + /* mmap the new file */ + + if ((dst = mmap(0, len, PROT_READ | PROT_WRITE, + MAP_FILE|MAP_SHARED, dst_fd, 0)) == MAP_FAILED) { + ui_error(op, "Unable to map destination file '%s' for " + "copying (%s)", tmpfile, strerror(errno)); + dst = NULL; + failed = TRUE; goto done; + } + + /* write the processed data out to the temporary file */ + + memcpy(dst, tmp, len); + +done: + + if (src) { + if (munmap(src, stat_buf.st_size) == -1) { + ui_error(op, "Unable to unmap source file '%s' after " + "copying (%s)", pe->file, + strerror(errno)); + } + } + + if (dst) { + if (munmap(dst, len) == -1) { + ui_error (op, "Unable to unmap destination file '%s' " + "after copying (%s)", tmpfile, strerror(errno)); + } + } + + if (src_fd != -1) close(src_fd); + if (dst_fd != -1) { + close(dst_fd); + /* in case an error occurred, delete the temporary file */ + if (failed) unlink(tmpfile); + } + + if (failed) { + nvfree(tmpfile); tmpfile = NULL; + } + + nvfree(tmp); + + return tmpfile; + +} /* process_template_files() */ + + + /* * process_libGL_la_files() - for any libGL.la files in the package, * copy them to a temporary file, replacing __GENERATED_BY__ and @@ -1417,145 +1687,200 @@ static char *nv_strreplace(char *src, char *orig, char *replace) void process_libGL_la_files(Options *op, Package *p) { - int i, n, src_fd, dst_fd, len; - struct stat stat_buf; - char *src, *dst, *tmp, *tmp0, *tmp1, *tmpfile; + int i, n; + char *tmpfile; + + char *tokens[3] = { "__LIBGL_PATH__", "__GENERATED_BY__", NULL }; + char *replacements[3] = { NULL, NULL, NULL }; int package_num_entries = p->num_entries; + replacements[1] = nvstrcat(PROGRAM_NAME, ": ", + NVIDIA_INSTALLER_VERSION, NULL); + for (i = 0; i < package_num_entries; i++) { if ((p->entries[i].flags & FILE_TYPE_LIBGL_LA)) { - src_fd = dst_fd = -1; - tmp0 = tmp1 = src = dst = tmpfile = NULL; - len = 0; - - /* open the file */ - - if ((src_fd = open(p->entries[i].file, O_RDONLY)) == -1) { - ui_error(op, "Unable to open '%s' for copying (%s)", - p->entries[i].file, strerror(errno)); - goto done; - } + replacements[0] = nvstrcat(op->opengl_prefix, + "/", p->entries[i].path, NULL); + + /* invalidate the template file */ - /* get the size of the file */ + p->entries[i].flags &= ~FILE_TYPE_MASK; + p->entries[i].dst = NULL; - if (fstat(src_fd, &stat_buf) == -1) { - ui_error(op, "Unable to determine size of '%s' (%s)", - p->entries[i].file, strerror(errno)); - goto done; + tmpfile = process_template_file(op, &p->entries[i], tokens, + replacements); + + if (tmpfile != NULL) { + /* add this new file to the package */ + + n = p->num_entries; + + p->entries = + (PackageEntry *) nvrealloc(p->entries, + (n + 1) * sizeof(PackageEntry)); + p->entries[n].file = tmpfile; + p->entries[n].path = p->entries[i].path; + p->entries[n].target = NULL; + p->entries[n].flags = ((p->entries[i].flags & FILE_CLASS_MASK) + | FILE_TYPE_LIBGL_LA); + p->entries[n].mode = p->entries[i].mode; + + p->entries[n].name = nvstrdup(p->entries[i].name); + + p->num_entries++; } - /* mmap the file */ + nvfree(replacements[0]); + } + } - if ((src = mmap(0, stat_buf.st_size, PROT_READ, - MAP_FILE|MAP_SHARED, src_fd, 0)) == (void *) -1) { - ui_error (op, "Unable to map source file '%s' for " - "copying (%s)", p->entries[i].file, strerror(errno)); - src = NULL; - goto done; - } + nvfree(replacements[1]); - if (!src) { - ui_log(op, "%s is empty; skipping.", p->entries[i].file); - goto done; - } +} /* process_libGL_la_files() */ - /* replace __LIBGL_PATH__ */ - tmp = nvstrcat(op->opengl_prefix, "/", p->entries[i].path, NULL); - tmp0 = nv_strreplace(src, "__LIBGL_PATH__", tmp); - nvfree(tmp); - /* replace __GENERATED_BY__ */ +/* + * process_dot_desktop_files() - for any .desktop files in the + * package, copy them to a temporary file, replacing __UTILS_PATH__ + * and __LIBGL_PATH__ as appropriate. Then, add the new file to + * the package list. + */ - tmp = nvstrcat(PROGRAM_NAME, ": ", NVIDIA_INSTALLER_VERSION, NULL); - tmp1 = nv_strreplace(tmp0, "__GENERATED_BY__", tmp); - nvfree(tmp); +void process_dot_desktop_files(Options *op, Package *p) +{ + int i, n; + char *tmpfile; - /* create a temporary file to store the processed libGL.la file */ - - tmpfile = nvstrcat(op->tmpdir, "/libGL.la-XXXXXX", NULL); - if ((dst_fd = mkstemp(tmpfile)) == -1) { - ui_error(op, "Unable to create temporary file (%s)", - strerror(errno)); - goto done; - } + char *tokens[3] = { "__UTILS_PATH__", "__DOCS_PATH__", NULL }; + char *replacements[3] = { NULL, NULL, NULL }; - /* set the size of the new file */ + int package_num_entries = p->num_entries; - len = strlen(tmp1); - - if (lseek(dst_fd, len - 1, SEEK_SET) == -1) { - ui_error(op, "Unable to set file size for '%s' (%s)", - tmpfile, strerror(errno)); - goto done; - } - if (write(dst_fd, "", 1) != 1) { - ui_error(op, "Unable to write file size for '%s' (%s)", - tmpfile, strerror(errno)); - goto done; - } + for (i = 0; i < package_num_entries; i++) { + if ((p->entries[i].flags & FILE_TYPE_DOT_DESKTOP)) { + + replacements[0] = nvstrcat(op->utility_prefix, + "/", UTILITY_BINARY_DST_PATH, NULL); + replacements[1] = nvstrcat(op->opengl_prefix, + "/", DOCUMENTATION_DST_PATH, NULL); - /* mmap the new file */ + /* invalidate the template file */ + + p->entries[i].flags &= ~FILE_TYPE_MASK; + p->entries[i].dst = NULL; - if ((dst = mmap(0, len, PROT_READ | PROT_WRITE, - MAP_FILE|MAP_SHARED, dst_fd, 0)) == (void *) -1) { - ui_error(op, "Unable to map destination file '%s' for " - "copying (%s)", tmpfile, strerror(errno)); - dst = NULL; - goto done; + tmpfile = process_template_file(op, &p->entries[i], tokens, + replacements); + if (tmpfile != NULL) { + /* add this new file to the package */ + + n = p->num_entries; + + p->entries = + (PackageEntry *) nvrealloc(p->entries, + (n + 1) * sizeof(PackageEntry)); + p->entries[n].file = tmpfile; + p->entries[n].path = p->entries[i].path; + p->entries[n].target = NULL; + p->entries[n].flags = ((p->entries[i].flags & FILE_CLASS_MASK) + | FILE_TYPE_DOT_DESKTOP); + p->entries[n].mode = p->entries[i].mode; + + p->entries[n].name = nvstrdup(p->entries[i].name); + + p->num_entries++; } - /* write the data out to the new file */ + nvfree(replacements[0]); + nvfree(replacements[1]); + } + } +} /* process_dot_desktop_files() */ - memcpy(dst, tmp1, len); - /* invalidate the template file */ +/* + * set_security_context() - set the security context of the file to 'shlib_t' + * Returns TRUE on success or if SELinux is disabled, FALSE otherwise + */ +int set_security_context(Options *op, const char *filename) +{ + char *cmd = NULL; + int ret = FALSE; + + if (op->selinux_enabled == FALSE) { + return TRUE; + } + + cmd = nvstrcat(op->utils[CHCON], " -t shlib_t ", filename, + NULL); + + ret = run_command(op, cmd, NULL, FALSE, 0, TRUE); + + ret = ((ret == 0) ? TRUE : FALSE); + if (cmd) nvfree(cmd); + + return ret; +} /* set_security_context() */ - p->entries[i].flags &= ~FILE_TYPE_MASK; - p->entries[i].dst = NULL; - /* add this new file to the package */ - - n = p->num_entries; - - p->entries = - (PackageEntry *) nvrealloc(p->entries, - (n + 1) * sizeof(PackageEntry)); - p->entries[n].file = tmpfile; - p->entries[n].path = p->entries[i].path; - p->entries[n].target = NULL; - p->entries[n].flags = ((p->entries[i].flags & FILE_CLASS_MASK) | - FILE_TYPE_LIBGL_LA); - p->entries[n].mode = p->entries[i].mode; - - p->entries[n].name = nvstrdup(p->entries[i].name); - - p->num_entries++; - done: +/* + * get_x_module_path() - assign op->x_module_path if it is not already + * set + */ - if (src) { - if (munmap(src, stat_buf.st_size) == -1) { - ui_error(op, "Unable to unmap source file '%s' after " - "copying (%s)", p->entries[i].file, - strerror(errno)); - } - } - - if (dst) { - if (munmap(dst, len) == -1) { - ui_error (op, "Unable to unmap destination file '%s' " - "after copying (%s)", tmpfile, strerror(errno)); - } - } +static int get_x_module_path(Options *op) +{ + char *dir = NULL; + char *lib; + int ret; - if (src_fd != -1) close(src_fd); - if (dst_fd != -1) close(dst_fd); - - if (tmp0) nvfree(tmp0); - if (tmp1) nvfree(tmp1); - } + /* + * if the path was already specified (ie: by a commandline + * option), then we are done + */ + + if (op->x_module_path) { + return TRUE; } -} /* process_libGL_la_files() */ + + /* ask pkg-config */ + + ret = run_command(op, "pkg-config --variable=moduledir xorg-server", + &dir, FALSE, 0, TRUE); + + if ((ret == 0) && directory_exists(op, dir)) { + op->x_module_path = dir; + return TRUE; + } + + nvfree(dir); + + /* build the X module path from the xfree86_prefix */ + + /* + * XXX kludge to determine the correct 'lib' vs 'lib64' path; + * normally, on 64-bit distributions, the X modules get installed + * in "/lib64/modules". However, on Debian, Ubuntu, or + * any 32-bit distribution, we use "/lib/modules" + */ + +#if defined(NV_X86_64) + if ((op->distro == DEBIAN || op->distro == UBUNTU)) { + lib = "lib"; + } else { + lib = "lib64"; + } +#else + lib = "lib"; +#endif + + op->x_module_path = nvstrcat(op->xfree86_prefix, + "/", lib, "/modules", NULL); + + return TRUE; + +} /* get_x_module_path() */ diff --git a/files.h b/files.h index 67a2896..f9fddc8 100644 --- a/files.h +++ b/files.h @@ -56,6 +56,11 @@ int nvrename(Options *op, const char *src, const char *dst); int check_for_existing_rpms(Options *op); int copy_directory_contents(Options *op, const char *src, const char *dst); int pack_precompiled_kernel_interface(Options *op, Package *p); + +char *process_template_file(Options *op, PackageEntry *pe, + char **tokens, char **replacements); void process_libGL_la_files(Options *op, Package *p); +void process_dot_desktop_files(Options *op, Package *p); +int set_security_context(Options *op, const char *filename); #endif /* __NVIDIA_INSTALLER_FILES_H__ */ diff --git a/gen-manpage-opts.c b/gen-manpage-opts.c new file mode 100644 index 0000000..440502e --- /dev/null +++ b/gen-manpage-opts.c @@ -0,0 +1,123 @@ +/* + * Prints the option help in a form that is suitable to include in the manpage. + */ +#include +#include +#include + +#include "nvidia-installer.h" +#include "option_table.h" + +static void print_option(const NVOption *o) +{ + char scratch[64], *s; + int j, len; + + int omitWhiteSpace; + + printf(".TP\n.BI "); + /* Print the name of the option */ + /* XXX We should backslashify the '-' characters in o->name. */ + if (o->flags & NVOPT_IS_BOOLEAN) { + /* "\-\-name, \-\-no\-name */ + printf("\"\\-\\-%s, \\-\\-no\\-%s", o->name, o->name); + } else if (isalnum(o->val)) { + /* "\-c, \-\-name */ + printf("\"\\-%c, \\-\\-%s", o->val, o->name); + } else { + /* "\-\-name */ + printf("\"\\-\\-%s", o->name); + } + + if (o->flags & NVOPT_HAS_ARGUMENT) { + len = strlen(o->name); + for (j = 0; j < len; j++) scratch[j] = toupper(o->name[j]); + scratch[len] = '\0'; + printf("=\" \"%s", scratch); + } + + printf("\"\n"); + + /* + * Print the option description: write each character one at a + * time (ugh) so that we can special-case a few characters: + * + * "[" --> "\n.I " + * "]" --> "\n" + * "-" --> "\-" + * + * Brackets are used to mark the text inbetween as italics. + * '-' is special cased so that we can backslashify it. + * + * XXX Each sentence should be on its own line! + */ + + omitWhiteSpace = 0; + + for (s = o->description; s && *s; s++) { + + switch (*s) { + case '[': + printf("\n.I "); + omitWhiteSpace = 0; + break; + case ']': + printf("\n"); + omitWhiteSpace = 1; + break; + case '-': + printf("\\-"); + omitWhiteSpace = 0; + break; + case ' ': + if (!omitWhiteSpace) { + printf("%c", *s); + } + break; + default: + printf("%c", *s); + omitWhiteSpace = 0; + break; + } + } + + printf("\n"); +} + +int main(int argc, char* argv[]) +{ + int i; + const NVOption *o; + + /* Print the "simple" options, i.e. the ones you get by running + * nvidia-installer --help. + */ + printf(".SH OPTIONS\n"); + for (i = 0; __options[i].name; i++) { + o = &__options[i]; + + if (!(o->flags & OPTION_HELP_ALWAYS)) + continue; + + if (!o->description) + continue; + + print_option(o); + } + + /* Print the advanced options. */ + printf(".SH \"ADVANCED OPTIONS\"\n"); + for (i = 0; __options[i].name; i++) { + o = &__options[i]; + + if (o->flags & OPTION_HELP_ALWAYS) + continue; + + if (!o->description) + continue; + + print_option(o); + } + + return 0; +} diff --git a/install-from-cwd.c b/install-from-cwd.c index 514b79f..f5e2db8 100644 --- a/install-from-cwd.c +++ b/install-from-cwd.c @@ -54,8 +54,7 @@ static Package *parse_manifest(Options *op); - - +static int install_kernel_module(Options *op, Package *p); /* @@ -117,77 +116,20 @@ int install_from_cwd(Options *op) */ if (!check_for_existing_driver(op, p)) return FALSE; - - /* determine where to install the kernel module */ - - if (!determine_kernel_module_installation_path(op)) goto failed; - /* - * do nvchooser-style logic to decide if we have a prebuilt kernel - * module for their kernel - * - * XXX One could make the argument that we should not actually do - * the building/linking now, but just add this to the list of - * operations and do it when we execute the operation list. I - * think it's better to make sure we have a kernel module early on - * -- a common problem for users will be not having a prebuilt - * kernel interface for their kernel, and not having the kernel - * headers installed, so it's better to catch that earlier on. - */ - - if (find_precompiled_kernel_interface(op, p)) { - - /* - * we have a prebuild kernel interface, so now link the kernel - * interface with the binary portion of the kernel module. - * - * XXX if linking fails, maybe we should fall through and - * attempt to build the kernel module? No, if linking fails, - * then there is something pretty seriously wrong... better to - * abort. - */ - - if (!link_kernel_module(op, p)) goto failed; + /* attempt to build a kernel module for the target kernel */ + if (!op->no_kernel_module) { + if (!install_kernel_module(op, p)) goto failed; } 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)) goto failed; - - /* - * we do not have a prebuilt kernel interface; thus we'll need - * to compile the kernel interface, so determine where the - * kernel header files are - */ - - if (!determine_kernel_source_path(op)) goto failed; - determine_kernel_output_path(op); - - /* - * make sure that the selected or default system compiler - * is compatible with the target kernel; the user may choose - * to override the check. - */ - if (!check_cc_version(op, p)) goto failed; - - /* and now, build the kernel interface */ - - if (!build_kernel_module(op, p)) goto failed; + ui_warn(op, "You specified the '--no-kernel-module' command line " + "option, nvidia-installer will not install a kernel " + "module as part of this driver installation, and it will " + "not remove existing NVIDIA kernel modules not part of " + "an earlier NVIDIA driver installation. Please ensure " + "that an NVIDIA kernel module matching this driver version " + "is installed seperately."); } - - /* - * if we got this far, we have a complete kernel module; test it - * to be sure it's OK - */ - - if (!test_kernel_module(op, p)) goto failed; - - /* add the kernel module to the list of things to install */ - - if (!add_kernel_module_to_package(op, p)) goto failed; /* * if we are only installing the kernel module, then remove @@ -215,13 +157,14 @@ int install_from_cwd(Options *op) select_tls_class(op, p); /* - * if the package contains any libGL.la files, process them - * (perform some search and replacing so that they reflect the - * correct installation path, etc) and add them to the - * packagelist to be installed. + * if the package contains any libGL.la or .desktop files, + * process them (perform some search and replacing so + * that they reflect the correct installation path, etc) + * and add them to the package list (files to be installed). */ process_libGL_la_files(op, p); + process_dot_desktop_files(op, p); #if defined(NV_X86_64) /* @@ -260,7 +203,7 @@ int install_from_cwd(Options *op) /* call the ui to get approval for the list of commands */ - if (!ui_approve_command_list(op, c, p->description)) return FALSE; + if (!ui_approve_command_list(op, c, "%s", p->description)) return FALSE; /* initialize the backup log file */ @@ -325,6 +268,97 @@ int install_from_cwd(Options *op) +/* + * install_kernel_module() - attempt to build and install a kernel + * module for the running kernel; we first check if a prebuilt kernel + * interface file exists. If yes, we try to link it into the final + * kernel module, else we try to build one from source. + * + * If we succeed in building a kernel module, we attempt to load it + * into the host kernel and add it to the list of files to install if + * the load attempt succeeds. + */ + +static int install_kernel_module(Options *op, Package *p) +{ + /* determine where to install the kernel module */ + + if (!determine_kernel_module_installation_path(op)) return FALSE; + + /* check '/proc/sys/kernel/modprobe' */ + + if (!check_proc_modprobe_path(op)) return FALSE; + + /* + * do nvchooser-style logic to decide if we have a prebuilt kernel + * module for their kernel + * + * XXX One could make the argument that we should not actually do + * the building/linking now, but just add this to the list of + * operations and do it when we execute the operation list. I + * think it's better to make sure we have a kernel module early on + * -- a common problem for users will be not having a prebuilt + * kernel interface for their kernel, and not having the kernel + * headers installed, so it's better to catch that earlier on. + */ + + if (find_precompiled_kernel_interface(op, p)) { + + /* + * we have a prebuild kernel interface, so now link the kernel + * interface with the binary portion of the kernel module. + * + * XXX if linking fails, maybe we should fall through and + * attempt to build the kernel module? No, if linking fails, + * then there is something pretty seriously wrong... better to + * abort. + */ + + if (!link_kernel_module(op, p)) return FALSE; + + } else { + /* + * make sure that the selected or default system compiler + * is compatible with the target kernel; the user may choose + * to override the check. + */ + if (!check_cc_version(op, p)) return FALSE; + + /* + * 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)) return FALSE; + + /* + * we do not have a prebuilt kernel interface; thus we'll need + * to compile the kernel interface, so determine where the + * kernel source files are. + */ + + if (!determine_kernel_source_path(op, p)) return FALSE; + + /* and now, build the kernel interface */ + + if (!build_kernel_module(op, p)) return FALSE; + } + + /* + * if we got this far, we have a complete kernel module; test it + * to be sure it's OK + */ + + if (!test_kernel_module(op, p)) return FALSE; + + /* add the kernel module to the list of things to install */ + + if (!add_kernel_module_to_package(op, p)) return FALSE; + + return TRUE; +} + + /* * add_this_kernel() - build a precompiled kernel interface for the * running kernel, and repackage the .run file to include the new @@ -341,7 +375,7 @@ int add_this_kernel(Options *op) /* find the kernel header files */ - if (!determine_kernel_source_path(op)) goto failed; + if (!determine_kernel_source_path(op, p)) goto failed; /* build the precompiled kernel interface */ @@ -424,13 +458,13 @@ static Package *parse_manifest (Options *op) /* the first line is the description */ line = 1; - p->description = get_next_line(manifest, &ptr); + p->description = get_next_line(manifest, &ptr, manifest, len); if (!p->description) goto invalid_manifest_file; /* the second line is the version */ line++; - p->version_string = get_next_line(ptr, &ptr); + p->version_string = get_next_line(ptr, &ptr, manifest, len); if (!p->version_string) goto invalid_manifest_file; if (!nvid_version(p->version_string, &p->major, &p->minor, &p->patch)) goto invalid_manifest_file; @@ -438,13 +472,13 @@ static Package *parse_manifest (Options *op) /* new third line is the kernel interface filename */ line++; - p->kernel_interface_filename = get_next_line(ptr, &ptr); + p->kernel_interface_filename = get_next_line(ptr, &ptr, manifest, len); if (!p->kernel_interface_filename) goto invalid_manifest_file; /* the fourth line is the kernel module name */ line++; - p->kernel_module_name = get_next_line(ptr, &ptr); + p->kernel_module_name = get_next_line(ptr, &ptr, manifest, len); if (!p->kernel_module_name) goto invalid_manifest_file; /* @@ -453,7 +487,7 @@ static Package *parse_manifest (Options *op) */ line++; - tmpstr = get_next_line(ptr, &ptr); + tmpstr = get_next_line(ptr, &ptr, manifest, len); if (!tmpstr) goto invalid_manifest_file; p->bad_modules = NULL; @@ -474,7 +508,7 @@ static Package *parse_manifest (Options *op) */ line++; - tmpstr = get_next_line(ptr, &ptr); + tmpstr = get_next_line(ptr, &ptr, manifest, len); if (!tmpstr) goto invalid_manifest_file; p->bad_module_filenames = NULL; @@ -491,7 +525,7 @@ static Package *parse_manifest (Options *op) /* the seventh line is the kernel module build directory */ line++; - p->kernel_module_build_directory = get_next_line(ptr, &ptr); + p->kernel_module_build_directory = get_next_line(ptr, &ptr, manifest, len); if (!p->kernel_module_build_directory) goto invalid_manifest_file; remove_trailing_slashes(p->kernel_module_build_directory); @@ -501,7 +535,8 @@ static Package *parse_manifest (Options *op) */ line++; - p->precompiled_kernel_interface_directory = get_next_line(ptr, &ptr); + 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); @@ -512,7 +547,7 @@ static Package *parse_manifest (Options *op) line++; do { - buf = get_next_line(ptr, &ptr); + buf = get_next_line(ptr, &ptr, manifest, len); if ((!buf) || (buf[0] == '\0')) { done = TRUE; } else { @@ -564,22 +599,32 @@ static Package *parse_manifest (Options *op) p->entries[n].flags |= FILE_TYPE_OPENGL_LIB; else if (strcmp(flag, "LIBGL_LA") == 0) p->entries[n].flags |= FILE_TYPE_LIBGL_LA; - else if (strcmp(flag, "XFREE86_LIB") == 0) - p->entries[n].flags |= FILE_TYPE_XFREE86_LIB; + else if (strcmp(flag, "XLIB_STATIC_LIB") == 0) + p->entries[n].flags |= FILE_TYPE_XLIB_STATIC_LIB; + else if (strcmp(flag, "XLIB_SHARED_LIB") == 0) + p->entries[n].flags |= FILE_TYPE_XLIB_SHARED_LIB; else if (strcmp(flag, "TLS_LIB") == 0) p->entries[n].flags |= FILE_TYPE_TLS_LIB; else if (strcmp(flag, "DOCUMENTATION") == 0) p->entries[n].flags |= FILE_TYPE_DOCUMENTATION; else if (strcmp(flag, "OPENGL_SYMLINK") == 0) p->entries[n].flags |= FILE_TYPE_OPENGL_SYMLINK; - else if (strcmp(flag, "XFREE86_SYMLINK") == 0) - p->entries[n].flags |= FILE_TYPE_XFREE86_SYMLINK; + else if (strcmp(flag, "XLIB_SYMLINK") == 0) + p->entries[n].flags |= FILE_TYPE_XLIB_SYMLINK; else if (strcmp(flag, "TLS_SYMLINK") == 0) p->entries[n].flags |= FILE_TYPE_TLS_SYMLINK; else if (strcmp(flag, "INSTALLER_BINARY") == 0) p->entries[n].flags |= FILE_TYPE_INSTALLER_BINARY; else if (strcmp(flag, "UTILITY_BINARY") == 0) p->entries[n].flags |= FILE_TYPE_UTILITY_BINARY; + else if (strcmp(flag, "DOT_DESKTOP") == 0) + p->entries[n].flags |= FILE_TYPE_DOT_DESKTOP; + else if (strcmp(flag, "XMODULE_STATIC_LIB") == 0) + p->entries[n].flags |= FILE_TYPE_XMODULE_STATIC_LIB; + else if (strcmp(flag, "XMODULE_SHARED_LIB") == 0) + p->entries[n].flags |= FILE_TYPE_XMODULE_SHARED_LIB; + else if (strcmp(flag, "XMODULE_SYMLINK") == 0) + p->entries[n].flags |= FILE_TYPE_XMODULE_SYMLINK; else { nvfree(flag); goto invalid_manifest_file; diff --git a/kernel.c b/kernel.c index 5a3dd6e..4670879 100644 --- a/kernel.c +++ b/kernel.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "nvidia-installer.h" #include "kernel.h" @@ -49,11 +50,11 @@ static char *default_kernel_module_installation_path(Options *op); static char *default_kernel_source_path(Options *op); static int check_for_loaded_kernel_module(Options *op, const char *); +static void check_for_warning_messages(Options *op); static int rmmod_kernel_module(Options *op, const char *); static PrecompiledInfo *download_updated_kernel_interface(Options*, Package*, const char*); -static int rivafb_check(Options *op, Package *p); -static void change_page_attr_check(Options *op, Package *p); +static int fbdev_check(Options *op, Package *p); static PrecompiledInfo *scan_dir(Options *op, Package *p, const char *directory_name, @@ -69,12 +70,12 @@ static char *guess_kernel_module_filename(Options *op); */ static const char install_your_kernel_source[] = -"Please make sure you have installed the kernel source files " -"for your kernel; on Red Hat Linux systems, for example, be " -"sure you have the 'kernel-source' rpm installed. If you know the " -"correct kernel source files are installed, you may specify the " -"kernel source path with the '--kernel-source-path' " -"commandline option."; +"Please make sure you have installed the kernel source files for " +"your kernel and that they are properly configured; on Red Hat " +"Linux systems, for example, be sure you have the 'kernel-source' " +"RPM installed. If you know the correct kernel source files are " +"installed, you may specify the kernel source path with the " +"'--kernel-source-path' command line option."; @@ -152,10 +153,11 @@ int determine_kernel_module_installation_path(Options *op) * FALSE if no kernel source tree was found. */ -int determine_kernel_source_path(Options *op) +int determine_kernel_source_path(Options *op, Package *p) { - char *result; - int count = 0; + char *CC, *cmd, *result; + char *source_file, *source_path; + int ret, count = 0; /* determine the kernel source path */ @@ -240,61 +242,51 @@ int determine_kernel_source_path(Options *op) } free(result); -#if 0 + if (!determine_kernel_output_path(op)) return FALSE; - /* - * XXX The following heurisitic is broken: distribution-provided - * 2.6 kernel sources may not contain compile.h, even though they - * are valid to compile kernel modules against. One suggestion - * has been to check for autoconf.h instead. Disabling this - * entire check for now... - */ + CC = getenv("CC"); + if (!CC) CC = "cc"; + + cmd = nvstrcat("sh ", p->kernel_module_build_directory, + "/conftest.sh ", CC, " ", CC, " ", + op->kernel_source_path, " ", + op->kernel_output_path, " ", + "get_uname", NULL); + + ret = run_command(op, cmd, &result, FALSE, 0, TRUE); + nvfree(cmd); - /* - * try to check that the kernel headers have been configured; this - * is complicated by the fact that 2.4 and 2.6 kernels have - * different header files. Here is the heuristic: - * - * if compile.h exists: - * this is a 2.6 kernel - * if $(KERNEL_SOURCES)/Makefile does not exist - * the kernel sources have not been configured - * - * if compile.h does not exit: - * this is a 2.4 kernel - * if modversions.h does not exist - * the kernel sources have not been configured - */ + if (ret != 0) { + ui_error(op, "Unable to determine the version of the kernel " + "sources located in '%s'. %s", + op->kernel_source_path, install_your_kernel_source); + free(result); + return FALSE; + } - compile_h = nvstrcat(op->kernel_source_path, - "/include/linux/compile.h", NULL); - - if (access(compile_h, F_OK) == 0) { - /* compile.h exists: this is a 2.6 kernel */ - result = nvstrcat(op->kernel_source_path, "/Makefile", NULL); + if (strncmp(result, "2.4", 3) == 0) { + source_file = nvstrcat(op->kernel_source_path, + "/include/linux/version.h", NULL); + source_path = op->kernel_source_path; } else { - /* compile.h does not exist: this is a 2.4 kernel */ - result = nvstrcat(op->kernel_source_path, - "/include/linux/modversions.h", NULL); + source_file = nvstrcat(op->kernel_output_path, + "/include/linux/version.h", NULL); + source_path = op->kernel_output_path; } - - free(compile_h); - - if (access(result, F_OK) != 0) { + free(result); + + if (access(source_file, F_OK) != 0) { ui_error(op, "The kernel header file '%s' does not exist. " "The most likely reason for this is that the kernel " "source files in '%s' have not been configured.", - result, op->kernel_source_path); - free(result); + source_file, source_path); return FALSE; } - - free(result); -#endif /* OK, we seem to have a path to a configured kernel source tree */ ui_log(op, "Kernel source path: '%s'\n", op->kernel_source_path); + ui_log(op, "Kernel output path: '%s'\n", op->kernel_output_path); return TRUE; @@ -420,7 +412,7 @@ int link_kernel_module(Options *op, Package *p) int build_kernel_module(Options *op, Package *p) { - char *result, *cmd, *tmp; + char *CC, *result, *cmd, *tmp; int len, ret; /* @@ -430,13 +422,15 @@ int build_kernel_module(Options *op, Package *p) touch_directory(op, p->kernel_module_build_directory); - + CC = getenv("CC"); + if (!CC) CC = "cc"; + /* * Check if conftest.sh can determine the Makefile, there's * no hope for the make rules if this fails. */ cmd = nvstrcat("sh ", p->kernel_module_build_directory, - "/conftest.sh cc ", + "/conftest.sh ", CC, " ", CC, " ", op->kernel_source_path, " ", op->kernel_output_path, " ", "select_makefile just_msg", NULL); @@ -445,13 +439,12 @@ int build_kernel_module(Options *op, Package *p) nvfree(cmd); if (ret != 0) { - ui_error(op, result); /* display conftest.sh's error message */ + ui_error(op, "%s", result); /* display conftest.sh's error message */ nvfree(result); return FALSE; } - if (!rivafb_check(op, p)) return FALSE; - change_page_attr_check(op, p); + if (!fbdev_check(op, p)) return FALSE; cmd = nvstrcat("cd ", p->kernel_module_build_directory, "; make print-module-filename", @@ -625,6 +618,46 @@ int build_kernel_interface(Options *op, Package *p) +/* + * check_for_warning_messages() - check if the kernel module detected + * problems with the target system and registered warning messages + * for us with the Linux /proc interface. If yes, show these messages + * to the user. + */ + +void check_for_warning_messages(Options *op) +{ + char *paths[2] = { "/proc/driver/nvidia/warnings", NULL }; + FTS *fts; + FTSENT *ent; + char *buf = NULL; + + fts = fts_open(paths, FTS_LOGICAL, NULL); + if (!fts) return; + + while ((ent = fts_read(fts)) != NULL) { + switch (ent->fts_info) { + case FTS_F: + if ((strlen(ent->fts_name) == 6) && + !strncmp("README", ent->fts_name, 6)) + break; + if (read_text_file(ent->fts_path, &buf)) { + ui_warn(op, "%s", buf); + nvfree(buf); + } + break; + default: + /* ignore this file entry */ + break; + } + } + + fts_close(fts); + +} /* check_for_warning_messages() */ + + + /* * test_kernel_module() - attempt to insmod the kernel module and then * rmmod it. Return TRUE if the insmod succeeded, or FALSE otherwise. @@ -676,10 +709,18 @@ int test_kernel_module(Options *op, Package *p) ret = run_command(op, cmd, &data, op->expert, 0, TRUE); if (ret != 0) { - ui_error(op, "Unable to load the kernel module '%s'. This is " - "most likely because the kernel module was built using " - "the wrong kernel source files. %s", - p->kernel_module_filename, install_your_kernel_source); + ui_error(op, "Unable to load the kernel module '%s'. This " + "happens most frequently when this kernel module was " + "built against the wrong or improperly configured " + "kernel sources, with a version of gcc that differs " + "from the one used to build the target kernel, or " + "if a driver such as rivafb/nvidiafb is present and " + "prevents the NVIDIA kernel module from obtaining " + "ownership of the NVIDIA graphics device(s).\n\n" + "Please see the log entries 'Kernel module load " + "error' and 'Kernel messages' at the end of the file " + "'%s' for more information.", + p->kernel_module_filename, op->log_file_name); /* * if in expert mode, run_command() would have caused this to @@ -690,21 +731,16 @@ int test_kernel_module(Options *op, Package *p) if (!op->expert) ui_log(op, "Kernel module load error: %s", data); ret = FALSE; + } else { nvfree(cmd); - nvfree(data); /* - * display/log the last five lines of the kernel ring buffer - * to provide further details on the load failure. + * check if the kernel module detected problems with this + * system's kernel and display any warning messages it may + * have prepared for us. */ - cmd = nvstrcat(op->utils[DMESG], " | ", - op->utils[TAIL], " -n 15", NULL); - - if (!run_command(op, cmd, &data, FALSE, 0, TRUE)) - ui_log(op, "Kernel messages:\n%s", data); - } else { - free(cmd); + check_for_warning_messages(op); /* * attempt to unload the kernel module, but don't abort if @@ -716,8 +752,22 @@ int test_kernel_module(Options *op, Package *p) ret = TRUE; } - if (cmd) free(cmd); - if (data) free(data); + nvfree(cmd); + nvfree(data); + + /* + * display/log the last few lines of the kernel ring buffer + * to provide further details in case of a load failure or + * to capture NVRM warning messages, if any. + */ + cmd = nvstrcat(op->utils[DMESG], " | ", + op->utils[TAIL], " -n 25", NULL); + + if (!run_command(op, cmd, &data, FALSE, 0, TRUE)) + ui_log(op, "Kernel messages:\n%s", data); + + nvfree(cmd); + nvfree(data); if (new_loglevel != 0) sysctl(name, 2, NULL, 0, &old_loglevel, len); @@ -755,8 +805,8 @@ int load_kernel_module(Options *op, Package *p) ret = TRUE; } - if (cmd) free(cmd); - if (data) free(data); + nvfree(cmd); + nvfree(data); return ret; @@ -782,7 +832,10 @@ int check_kernel_module_version(Options *op, Package *p) int eof; fp = fopen(NVIDIA_VERSION_PROC_FILE, "r"); + if (!fp) + return FALSE; buf = fget_next_line(fp, &eof); + fclose(fp); if (!nvid_version(buf, &proc_major, &proc_minor, &proc_patch)) { free(buf); @@ -1260,6 +1313,7 @@ download_updated_kernel_interface(Options *op, Package *p, { int fd = -1; int dst_fd = -1; + int length; char *url = NULL; char *tmpfile = NULL; char *dstfile = NULL; @@ -1295,10 +1349,12 @@ download_updated_kernel_interface(Options *op, Package *p, /* get the length of the file */ if (fstat(fd, &stat_buf) == -1) goto done; + + length = stat_buf.st_size; /* map the file into memory for easier reading */ - str = mmap(0, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0); + str = mmap(0, length, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0); if (str == (void *) -1) goto done; /* @@ -1309,7 +1365,7 @@ download_updated_kernel_interface(Options *op, Package *p, ptr = str; while (TRUE) { - buf = get_next_line(ptr, &ptr); + buf = get_next_line(ptr, &ptr, str, length); if ((!buf) || (buf[0] == '\0')) goto done; s = strstr(buf, ":::"); @@ -1432,26 +1488,14 @@ int check_cc_version(Options *op, Package *p) return TRUE; } - /* - * Check if the libc development headers are installed; we need - * these to build the gcc version check utility. - */ - if (access("/usr/include/stdio.h", F_OK) == -1) { - ui_error(op, "You do not appear to have libc header files " - "installed on your system. Please install your " - "distribution's libc development package."); - return FALSE; - } - CC = getenv("CC"); if (!CC) CC = "cc"; ui_log(op, "Performing CC test with CC=\"%s\".", CC); cmd = nvstrcat("sh ", p->kernel_module_build_directory, - "/conftest.sh ", CC, " ", - op->kernel_source_path, " ", - op->kernel_output_path, " ", + "/conftest.sh ", CC, " ", CC, " ", + "DUMMY_SOURCE DUMMY_OUTPUT ", "cc_sanity_check just_msg", NULL); ret = run_command(op, cmd, &result, FALSE, 0, TRUE); @@ -1479,20 +1523,23 @@ int check_cc_version(Options *op, Package *p) /* - * rivafb_check() - run the rivafb_sanity_check conftest; if the test - * fails, print the error message from the test and abort driver - * installation. + * fbdev_check() - run the rivafb_sanity_check and the nvidiafb_sanity_check + * conftests; if either test fails, print the error message from the test + * and abort the driver installation. */ -static int rivafb_check(Options *op, Package *p) +static int fbdev_check(Options *op, Package *p) { - char *cmd, *result; + char *CC, *cmd, *result; int ret; + CC = getenv("CC"); + if (!CC) CC = "cc"; + ui_log(op, "Performing rivafb check."); cmd = nvstrcat("sh ", p->kernel_module_build_directory, - "/conftest.sh cc ", + "/conftest.sh ", CC, " ", CC, " ", op->kernel_source_path, " ", op->kernel_output_path, " ", "rivafb_sanity_check just_msg", NULL); @@ -1501,45 +1548,36 @@ static int rivafb_check(Options *op, Package *p) nvfree(cmd); - if (ret == 0) return TRUE; - - ui_error(op, result); - - nvfree(result); - - return FALSE; - -} /* rivafb_check() */ - - -/* - * change_page_attr_check() - run the change_page_attr_sanity_check - * conftest; if the test fails, print a warning messages, but continue - * the installation. - */ - -static void change_page_attr_check(Options *op, Package *p) -{ -#if defined(NV_X86_64) - char *cmd, *result; - int ret; + if (ret != 0) { + ui_error(op, "%s", result); + nvfree(result); - ui_log(op, "Performing change_page_attr() check."); + return FALSE; + } + ui_log(op, "Performing nvidiafb check."); + cmd = nvstrcat("sh ", p->kernel_module_build_directory, - "/conftest.sh cc ", + "/conftest.sh ", CC, " ", CC, " ", op->kernel_source_path, " ", op->kernel_output_path, " ", - "change_page_attr_sanity_check just_msg", NULL); + "nvidiafb_sanity_check just_msg", NULL); ret = run_command(op, cmd, &result, FALSE, 0, TRUE); + nvfree(cmd); - if (result && *result) ui_warn(op, result); - nvfree(result); + if (ret != 0) { + ui_error(op, "%s", result); + nvfree(result); -#endif /* NV_X86_64 */ -} + return FALSE; + } + + return TRUE; + + +} /* fbdev_check() */ diff --git a/kernel.h b/kernel.h index 686e60c..48962a2 100644 --- a/kernel.h +++ b/kernel.h @@ -28,7 +28,7 @@ #include "nvidia-installer.h" int determine_kernel_module_installation_path (Options*); -int determine_kernel_source_path (Options*); +int determine_kernel_source_path (Options*, Package*); int determine_kernel_output_path (Options*); int link_kernel_module (Options*, Package*); int check_cc_version (Options*, Package*); diff --git a/misc.c b/misc.c index 6c1c505..8d2331e 100644 --- a/misc.c +++ b/misc.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -300,7 +301,7 @@ int check_runlevel(Options *op) "this may cause problems. For example: some " "distributions that use devfs do not run the devfs " "daemon in runlevel 1, making it difficult for " - "nvidia-installer to correctly setup the kernel " + "`nvidia-installer` to correctly setup the kernel " "module configuration files. It is recommended " "that you quit installation now and switch to " "runlevel 3 (`telinit 3`) before installing.\n\n" @@ -383,9 +384,13 @@ char *fget_next_line(FILE *fp, int *eof) if (buflen == len) { /* buffer isn't big enough -- grow it */ buflen += NV_LINE_LEN; tmpbuf = (char *) nvalloc (buflen); + if (!tmpbuf) { + if (buf) nvfree(buf); + return NULL; + } if (buf) { memcpy (tmpbuf, buf, len); - free (buf); + nvfree(buf); } buf = tmpbuf; c = buf + len; @@ -411,11 +416,15 @@ char *fget_next_line(FILE *fp, int *eof) /* - * get_next_line() - this function scans for the next newline or - * carriage return in buf. If non-NULL, the passed-by-reference - * parameter e is set to point to the next printable character in the - * buffer, or NULL if EOF is encountered. + * get_next_line() - this function scans for the next newline, + * carriage return, NUL terminator, or EOF in buf. If non-NULL, the + * passed-by-reference parameter 'end' is set to point to the next + * printable character in the buffer, or NULL if EOF is encountered. * + * If the parameter 'start' is non-NULL, then that is interpretted as + * the start of the buffer string, and we check that we never walk + * 'length' bytes past 'start'. + * * On success, a newly allocated buffer is allocated containing the * next line of text (with a NULL terminator in place of the * newline/carriage return). @@ -423,27 +432,46 @@ char *fget_next_line(FILE *fp, int *eof) * On error, NULL is returned. */ -char *get_next_line(char *buf, char **e) +char *get_next_line(char *buf, char **end, char *start, int length) { char *c, *retbuf; int len; - if (e) *e = NULL; - - if ((!buf) || (*buf == '\0') || (*buf == EOF)) return NULL; + if (start && (length < 1)) return NULL; +#define __AT_END(_start, _current, _length) \ + ((_start) && (((_current) - (_start)) >= (_length))) + + if (end) *end = NULL; + + if ((!buf) || + __AT_END(start, buf, length) || + (*buf == '\0') || + (*buf == EOF)) return NULL; + c = buf; - while ((*c != '\0') && (*c != EOF) && (*c != '\n') && (*c != '\r')) c++; + + while ((!__AT_END(start, c, length)) && + (*c != '\0') && + (*c != EOF) && + (*c != '\n') && + (*c != '\r')) c++; len = c - buf; retbuf = nvalloc(len + 1); strncpy(retbuf, buf, len); retbuf[len] = '\0'; - if (e) { - while ((*c != '\0') && (*c != EOF) && (!isprint(*c))) c++; - if ((*c == '\0') || (*c == EOF)) *e = NULL; - else *e = c; + if (end) { + while ((!__AT_END(start, c, length)) && + (*c != '\0') && + (*c != EOF) && + (!isprint(*c))) c++; + + if (__AT_END(start, c, length) || + (*c == '\0') || + (*c == EOF)) *end = NULL; + else *end = c; } return retbuf; @@ -481,6 +509,7 @@ int run_command(Options *op, const char *cmd, char **data, int output, int n, len, buflen, ret; char *cmd2, *buf, *tmpbuf; FILE *stream = NULL; + struct sigaction act, old_act; float percent; if (data) *data = NULL; @@ -500,6 +529,21 @@ int run_command(Options *op, const char *cmd, char **data, int output, cmd2 = nvstrdup(cmd); } + /* + * XXX: temporarily ignore SIGWINCH; our child process inherits + * this disposition and will likewise ignore it (by default). + * This fixes cases where child processes abort after receiving + * SIGWINCH when its caught in the parent process. + */ + if (op->sigwinch_workaround) { + act.sa_handler = SIG_IGN; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + if (sigaction(SIGWINCH, &act, &old_act) < 0) + old_act.sa_handler = NULL; + } + /* * Open a process by creating a pipe, forking, and invoking the * command. @@ -537,7 +581,7 @@ int run_command(Options *op, const char *cmd, char **data, int output, if (fgets(buf + len, buflen - len, stream) == NULL) break; - if (output) ui_command_output(op, buf + len); + if (output) ui_command_output(op, "%s", buf + len); len += strlen(buf + len); @@ -545,6 +589,14 @@ int run_command(Options *op, const char *cmd, char **data, int output, n++; if (n > status) n = status; percent = (float) n / (float) status; + + /* + * 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); + ui_status_update(op, percent, NULL); } } /* while (1) */ @@ -553,6 +605,13 @@ int run_command(Options *op, const char *cmd, char **data, int output, ret = pclose(stream); + /* + * Restore the SIGWINCH signal disposition and handler, if any, + * to their original values. + */ + if (op->sigwinch_workaround) + sigaction(SIGWINCH, &old_act, NULL); + /* if the last character in the buffer is a newline, null it */ if ((len > 0) && (buf[len-1] == '\n')) buf[len-1] = '\0'; @@ -566,6 +625,54 @@ int run_command(Options *op, const char *cmd, char **data, int output, +/* + * read_text_file() - open a text file, read its contents and return + * them to the caller in a newly allocated buffer. Returns TRUE on + * success and FALSE on failure. + */ + +int read_text_file(const char *filename, char **buf) +{ + FILE *fp; + int index = 0, buflen = 0; + int eof = FALSE; + char *line, *tmpbuf; + + *buf = NULL; + + fp = fopen(filename, "r"); + if (!fp) + return FALSE; + + while (((line = fget_next_line(fp, &eof)) + != NULL) && !eof) { + if ((index + strlen(line) + 1) > buflen) { + buflen += 2 * strlen(line); + tmpbuf = (char *)nvalloc(buflen); + if (!tmpbuf) { + if (*buf) nvfree(*buf); + fclose(fp); + return FALSE; + } + if (*buf) { + memcpy(tmpbuf, *buf, index); + nvfree(*buf); + } + *buf = tmpbuf; + } + + index += sprintf(*buf + index, "%s\n", line); + nvfree(line); + } + + fclose(fp); + + return TRUE; + +} /* read_text_file() */ + + + /* * find_system_utils() - search the $PATH (as well as some common * additional directories) for the utilities that the installer will @@ -591,7 +698,14 @@ int find_system_utils(Options *op) { "cut", "coreutils" } }; - int i; + /* keep in sync with the SystemOptionalUtils enum type */ + const struct { const char *util, *package; } optional_utils[] = { + { "chcon", "selinux" }, + { "selinuxenabled", "selinux" }, + { "getenforce", "selinux" } + }; + + int i, j; ui_expert(op, "Searching for system utilities:"); @@ -613,6 +727,17 @@ int find_system_utils(Options *op) needed_utils[i].util, op->utils[i]); } + for (j = 0, i = MAX_SYSTEM_UTILS; i < MAX_SYSTEM_OPTIONAL_UTILS; i++, j++) { + + op->utils[i] = find_system_util(optional_utils[j].util); + if (op->utils[i]) { + ui_expert(op, "found `%s` : `%s`", + optional_utils[j].util, op->utils[i]); + } else { + op->utils[i] = NULL; + } + } + return TRUE; } /* find_system_utils() */ @@ -651,7 +776,7 @@ static Util __module_utils_linux24[] = { int find_module_utils(Options *op) { - int i, j = 0; + int i, j; Util *needed_utils = __module_utils; if (strncmp(get_kernel_name(op), "2.4", 3) == 0) @@ -661,7 +786,7 @@ int find_module_utils(Options *op) /* search the PATH for each utility */ - for (i = MAX_SYSTEM_UTILS; i < MAX_UTILS; i++, j++) { + for (j=0, i = MAX_SYSTEM_OPTIONAL_UTILS; i < MAX_UTILS; i++, j++) { op->utils[i] = find_system_util(needed_utils[j].util); if (!op->utils[i]) { ui_error(op, "Unable to find the module utility `%s`; please " @@ -682,6 +807,78 @@ int find_module_utils(Options *op) } /* find_module_utils() */ +/* + * check_proc_modprobe_path() - check if the modprobe path reported + * via /proc matches the one determined earlier; also check if it can + * be accessed/executed. + */ + +#define PROC_MODPROBE_PATH_FILE "/proc/sys/kernel/modprobe" + +int check_proc_modprobe_path(Options *op) +{ + FILE *fp; + char *buf = NULL; + + fp = fopen(PROC_MODPROBE_PATH_FILE, "r"); + if (fp) { + buf = fget_next_line(fp, NULL); + fclose(fp); + } + + if (buf && strcmp(buf, op->utils[MODPROBE])) { + if (access(buf, F_OK | X_OK) == 0) { + ui_warn(op, "The path to the `modprobe` utility reported by " + "'%s', `%s`, differs from the path determined by " + "`nvidia-installer`, `%s`. Please verify that `%s` " + "works correctly and correct the path in '%s' if " + "it does not.", + PROC_MODPROBE_PATH_FILE, buf, op->utils[MODPROBE], + buf, PROC_MODPROBE_PATH_FILE); + return TRUE; + } else { + ui_error(op, "The path to the `modprobe` utility reported by " + "'%s', `%s`, differs from the path determined by " + "`nvidia-installer`, `%s`, and does not appear to " + "point to a valid `modprobe` binary. Please correct " + "the path in '%s'.", + PROC_MODPROBE_PATH_FILE, buf, op->utils[MODPROBE], + PROC_MODPROBE_PATH_FILE); + return FALSE; + } + } else if (!buf && strcmp("/sbin/modprobe", op->utils[MODPROBE])) { + if (access(buf, F_OK | X_OK) == 0) { + ui_warn(op, "The file '%s' is unavailable, the X server will " + "use `/sbin/modprobe` as the path to the `modprobe` " + "utility. This path differs from the one determined " + "by `nvidia-installer`, `%s`. Please verify that " + "`/sbin/modprobe` works correctly or mount the /proc " + "file system and verify that '%s' reports the " + "correct path.", + PROC_MODPROBE_PATH_FILE, op->utils[MODPROBE], + PROC_MODPROBE_PATH_FILE); + return TRUE; + } else { + ui_error(op, "The file '%s' is unavailable, the X server will " + "use `/sbin/modprobe` as the path to the `modprobe` " + "utility. This path differs from the one determined " + "by `nvidia-installer`, `%s`, and does not appear to " + "point to a valid `modprobe` binary. Please create " + "a symbolic link from `/sbin/modprobe` to `%s` or " + "mount the /proc file system and verify that '%s' " + "reports the correct path.", + PROC_MODPROBE_PATH_FILE, op->utils[MODPROBE], + op->utils[MODPROBE], PROC_MODPROBE_PATH_FILE); + return FALSE; + } + } + nvfree(buf); + + return TRUE; + +} /* check_proc_modprobe_path() */ + + /* * check_development_tools() - check if the development tools needed * to build custom kernel interfaces are available. @@ -705,7 +902,7 @@ int check_development_tools(Options *op) if (!tool) { ui_error(op, "Unable to find the development tool `%s` in " "your path; please make sure that you have the " - "package '%s' installed. If %s is installed on your " + "package '%s' installed. If %s is installed on your " "system, then please check that `%s` is in your " "PATH.", needed_tools[i].tool, needed_tools[i].package, @@ -716,6 +913,17 @@ int check_development_tools(Options *op) ui_expert(op, "found `%s` : `%s`", needed_tools[i].tool, tool); } + /* + * Check if the libc development headers are installed; we need + * these to build the gcc version check utility. + */ + if (access("/usr/include/stdio.h", F_OK) == -1) { + ui_error(op, "You do not appear to have libc header files " + "installed on your system. Please install your " + "distribution's libc development package."); + return FALSE; + } + return TRUE; } /* check_development_tools() */ @@ -917,7 +1125,7 @@ void should_install_opengl_headers(Options *op, Package *p) void should_install_compat32_files(Options *op, Package *p) { #if defined(NV_X86_64) - int i, have_compat32_files = FALSE; + int i, have_compat32_files = FALSE, install_compat32_files; /* * first, scan through the package to see if we have any @@ -934,8 +1142,30 @@ void should_install_compat32_files(Options *op, Package *p) if (!have_compat32_files) return; - if (!ui_yes_no(op, TRUE, "Install NVIDIA's 32bit compatibility " - "OpenGL libraries?")) { + /* + * Ask the user if the 32-bit compatibility libraries are + * to be installed. If yes, check if the chosen prefix + * exists. If not, notify the user and ask him/her if the + * files are to be installed anyway. + */ + install_compat32_files = ui_yes_no(op, TRUE, + "Install NVIDIA's 32-bit compatibility OpenGL " + "libraries?"); + + if (install_compat32_files && op->compat32_prefix && + access(op->compat32_prefix, F_OK) < 0) { + install_compat32_files = ui_yes_no(op, FALSE, + "The NVIDIA 32-bit compatibility OpenGL libraries are " + "to be installed relative to the prefix '%s'; however, " + "this directory does not exit. Please consult your " + "distribution's documentation to confirm the correct " + "installation prefix for 32-bit compatiblity libraries." + "\n\nDo you wish to install the 32-bit NVIDIA OpenGL " + "compatibility libraries anyway?", + op->compat32_prefix); + } + + if (!install_compat32_files) { for (i = 0; i < p->num_entries; i++) { if (p->entries[i].flags & FILE_CLASS_COMPAT32) { /* invalidate file */ @@ -1244,6 +1474,17 @@ static int tls_test_internal(Options *op, int which_tls, goto done; } + if (set_security_context(op, dso_tmpfile) == FALSE) { + /* We are on a system with SELinux and the chcon command failed. + * Assume that the system is recent enough to have the new TLS + */ + ui_warn(op, "Unable to set the security context on file %s; " + "assuming new tls.", + dso_tmpfile); + ret = TRUE; + goto done; + } + /* run the test */ cmd = nvstrcat(tmpfile, " ", dso_tmpfile, NULL); @@ -1355,6 +1596,34 @@ void collapse_multiple_slashes(char *s) } + +/* + * is_symbolic_link_to() - check if the file with path 'path' is + * a symbolic link pointing to 'dest'. Returns TRUE if this is + * the case; if the file is not a symbolic link if it doesn't point + * to 'dest', is_symbolic_link_to() returns FALSE. + */ + +int is_symbolic_link_to(const char *path, const char *dest) +{ + struct stat stat_buf0, stat_buf1; + + if ((lstat(path, &stat_buf0) != 0) + || !S_ISLNK(stat_buf0.st_mode)) + return FALSE; + + if ((stat(path, &stat_buf0) == 0) && + (stat(dest, &stat_buf1) == 0) && + (stat_buf0.st_dev == stat_buf1.st_dev) && + (stat_buf0.st_ino == stat_buf1.st_ino)) + return TRUE; + + return FALSE; + +} /* is_symbolic_link_to() */ + + + /* * rtld_test_internal() - this routine writes the test binaries to a file * and performs the test; the caller (rtld_test()) selects which array data @@ -1367,9 +1636,10 @@ static int rtld_test_internal(Options *op, Package *p, const int test_array_size, int compat_32_libs) { - int i, ret = TRUE; + int fd, i, found = TRUE, ret = TRUE; char *name = NULL, *cmd = NULL, *data = NULL; char *tmpfile, *s; + char *tmpfile1 = NULL; struct stat stat_buf0, stat_buf1; if ((test_array == NULL) || (test_array_size == 0)) { @@ -1390,6 +1660,19 @@ static int rtld_test_internal(Options *op, Package *p, goto done; } + /* create another temporary file */ + + tmpfile1 = nvstrcat(op->tmpdir, "/nv-tmp-XXXXXX", NULL); + + fd = mkstemp(tmpfile1); + if (fd == -1) { + ui_warn(op, "Unable to create a temporary file for the runtime " + "configuration test program (%s); assuming successful " + "installation.", strerror(errno)); + goto done; + } + close(fd); + /* perform the test(s) */ for (i = 0; i < p->num_entries; i++) { @@ -1420,27 +1703,52 @@ static int rtld_test_internal(Options *op, Package *p, if (!s) goto next; *(s + strlen(".so.1")) = '\0'; - cmd = nvstrcat(op->utils[LDD], " ", tmpfile, " | ", - op->utils[GREP], " ", name, " | ", - op->utils[CUT], " -d \" \" -f 3", NULL); + cmd = nvstrcat(op->utils[LDD], " ", tmpfile, " > ", tmpfile1, NULL); - if (run_command(op, cmd, &data, FALSE, 0, TRUE)) { + if (run_command(op, cmd, NULL, FALSE, 0, TRUE)) { ui_warn(op, "Unable to perform the runtime configuration " - "check (%s); assuming successful installation.", - strerror(errno)); + "check for library '%s' ('%s'); assuming successful " + "installation.", name, p->entries[i].dst); goto done; } + cmd = nvstrcat(op->utils[GREP], " ", name, " ", tmpfile1, + " | ", op->utils[CUT], " -d \" \" -f 3", NULL); + + if (run_command(op, cmd, &data, FALSE, 0, TRUE) || + (data == NULL)) { + ui_warn(op, "Unable to perform the runtime configuration " + "check for library '%s' ('%s'); assuming successful " + "installation.", name, p->entries[i].dst); + goto done; + } + + if (!strcmp(data, "not") || !strlen(data)) { + /* + * If the library didn't show up in ldd's output or + * wasn't found, set 'found' to false and notify the + * user with a more meaningful message below. + */ + free(data); data = NULL; + found = FALSE; + } else { + /* + * Double slashes in /etc/ld.so.conf make it all the + * way to ldd's output on some systems. Strip them + * here to make sure they don't cause a false failure. + */ + collapse_multiple_slashes(data); + } + nvfree(name); name = NULL; name = nvstrdup(p->entries[i].dst); if (!name) goto next; - collapse_multiple_slashes(data); s = strstr(name, ".so.1"); if (!s) goto next; *(s + strlen(".so.1")) = '\0'; - if ((strcmp(data, name) != 0)) { + if (!found || (strcmp(data, name) != 0)) { /* * XXX Handle the case where the same library is * referred to, once directly and once via a symbolic @@ -1450,21 +1758,46 @@ static int rtld_test_internal(Options *op, Package *p, if ((stat(data, &stat_buf0) == 0) && (stat(name, &stat_buf1) == 0) && - (memcmp(&stat_buf0, &stat_buf1, sizeof(struct stat)) == 0)) + (stat_buf0.st_dev == stat_buf1.st_dev) && + (stat_buf0.st_ino == stat_buf1.st_ino)) goto next; - ui_error(op, "The runtime configuration check failed for " - "library '%s' (expected: '%s', found: '%s'). " - "The most likely reason for this is that conflicting " - "OpenGL libraries are installed in a location " - "not inspected by nvidia-installer. Please be sure " - "you have uninstalled any third-party OpenGL and " - "third-party graphics driver packages.", - p->entries[i].name, name, - (data && strlen(data)) ? data : "(not found)"); - - ret = FALSE; - goto done; + if (!found && !compat_32_libs) { + ui_error(op, "The runtime configuration check failed for " + "library '%s' (expected: '%s', found: (not found)). " + "The most likely reason for this is that the library " + "was installed to the wrong location or that your " + "system's dynamic loader configuration needs to be " + "updated. Please check the OpenGL library installation " + "prefix and/or the dynamic loader configuration.", + p->entries[i].name, name); + ret = FALSE; + goto done; +#if defined(NV_X86_64) + } else if (!found) { + ui_warn(op, "The runtime configuration check failed for " + "library '%s' (expected: '%s', found: (not found)). " + "The most likely reason for this is that the library " + "was installed to the wrong location or that your " + "system's dynamic loader configuration needs to be " + "updated. Please check the 32-bit OpenGL compatibility " + "library installation prefix and/or the dynamic loader " + "configuration.", + p->entries[i].name, name); + goto next; +#endif /* NV_X86_64 */ + } else { + ui_error(op, "The runtime configuration check failed for the " + "library '%s' (expected: '%s', found: '%s'). The " + "most likely reason for this is that conflicting " + "OpenGL libraries are installed in a location not " + "inspected by `nvidia-installer`. Please be sure you " + "have uninstalled any third-party OpenGL and/or " + "third-party graphics driver packages.", + p->entries[i].name, name, data); + ret = FALSE; + goto done; + } } next: @@ -1478,6 +1811,10 @@ static int rtld_test_internal(Options *op, Package *p, unlink(tmpfile); nvfree(tmpfile); } + if (tmpfile1) { + unlink(tmpfile1); + nvfree(tmpfile1); + } nvfree(name); nvfree(cmd); @@ -1499,8 +1836,35 @@ static int rtld_test_internal(Options *op, Package *p, Distribution get_distribution(Options *op) { + FILE *fp; + char *line = NULL, *ptr; + int eof = FALSE; + if (access("/etc/SuSE-release", F_OK) == 0) return SUSE; if (access("/etc/UnitedLinux-release", F_OK) == 0) return UNITED_LINUX; + if (access("/etc/gentoo-release", F_OK) == 0) return GENTOO; + + /* + * Attempt to determine if the host system is 'Ubuntu Linux' + * based by checking for a line matching DISTRIB_ID=Ubuntu in + * the file /etc/lsb-release. + */ + fp = fopen("/etc/lsb-release", "r"); + if (fp != NULL) { + while (((line = fget_next_line(fp, &eof)) + != NULL) && !eof) { + ptr = strstr(line, "DISTRIB_ID"); + if (ptr != NULL) { + fclose(fp); + while (ptr != NULL && *ptr != '=') ptr++; + if (ptr != NULL && *ptr == '=') ptr++; + if (ptr != NULL && *ptr != '\0') + if (!strcasecmp(ptr, "Ubuntu")) return UBUNTU; + break; + } + } + } + if (access("/etc/debian_version", F_OK) == 0) return DEBIAN; return OTHER; @@ -1553,7 +1917,68 @@ int check_for_running_x(Options *op) } /* check_for_running_x() */ - +/* + * check_selinux() - check if selinux is available. + * Sets the variable op->selinux_enabled. + * Returns TRUE on success, FALSE otherwise. + */ +int check_selinux(Options *op) +{ + int selinux_available = TRUE; + + if (op->utils[CHCON] == NULL || + op->utils[SELINUX_ENABLED] == NULL || + op->utils[GETENFORCE] == NULL) { + selinux_available = FALSE; + } + + switch (op->selinux_option) { + case SELINUX_FORCE_YES: + if (selinux_available == FALSE) { + /* We have set the option --force-selinux=yes but SELinux + * is not available on this system */ + ui_error(op, "Invalid option '--force-selinux=yes'; " + "SELinux is not available on this system"); + return FALSE; + } + op->selinux_enabled = TRUE; + break; + + case SELINUX_FORCE_NO: + if (selinux_available == TRUE) { + char *data = NULL; + int ret = run_command(op, op->utils[GETENFORCE], &data, + FALSE, 0, TRUE); + + if ((ret != 0) || (!data)) { + ui_warn(op, "Cannot check the current mode of SELinux; " + "Command getenforce() failed"); + } else if (!strcmp(data, "Enforcing")) { + /* We have set the option --force-selinux=no but SELinux + * is enforced on this system */ + ui_warn(op, "The option '--force-selinux' has been set to 'no', " + "but SELinux is enforced on this system; " + "The X server may not start correctly "); + } + nvfree(data); + } + op->selinux_enabled = FALSE; + break; + + case SELINUX_DEFAULT: + op->selinux_enabled = FALSE; + if (selinux_available == TRUE) { + int ret = run_command(op, op->utils[SELINUX_ENABLED], NULL, + FALSE, 0, TRUE); + if (ret == 0) { + op->selinux_enabled = TRUE; + } + } + break; + } + + return TRUE; +} /* check_selinux */ /* * nv_format_text_rows() - this function breaks the given string str * into some number of rows, where each row is not longer than the diff --git a/misc.h b/misc.h index 532fc5a..29228c8 100644 --- a/misc.h +++ b/misc.h @@ -68,6 +68,18 @@ do { \ } \ } while (0) +/* + * NV_STRCAT() - takes a dynamically allocated string followed by a + * NULL-terminated list of arbitrary strings and concatenates the + * strings with nvstrcat(); the newly allocated string replaces the + * original one, which is freed. + */ +#define NV_STRCAT(str, args...) \ +do { \ + char *__tmp_str = (str); \ + (str) = nvstrcat(__tmp_str, ##args); \ + nvfree(__tmp_str); \ +} while (0) void *nvalloc(size_t size); void *nvrealloc(void *ptr, size_t size); @@ -82,11 +94,14 @@ int check_euid(Options *op); int check_runlevel(Options *op); int adjust_cwd(Options *op, const char *program_name); char *fget_next_line(FILE *fp, int *eof); -char *get_next_line(char *buf, char **e); +char *get_next_line(char *buf, char **e, char *start, int length); int run_command(Options *op, const char *cmd, char **data, int output, int status, int redirect); +int read_text_file(const char *filename, char **buf); int find_system_utils(Options *op); int find_module_utils(Options *op); +int check_selinux(Options *op); +int check_proc_modprobe_path(Options *op); int check_development_tools(Options *op); int nvid_version (const char *str, int *major, int *minor, int *patch); int continue_after_error(Options *op, const char *fmt, ...); @@ -97,6 +112,8 @@ void check_installed_files_from_package(Options *op, Package *p); unsigned int get_installable_file_mask(Options *op); int tls_test(Options *op, int compat_32_libs); int check_runtime_configuration(Options *op, Package *p); +void collapse_multiple_slashes(char *s); +int is_symbolic_link_to(const char *path, const char *dest); Distribution get_distribution(Options *op); int check_for_running_x(Options *op); diff --git a/mkprecompiled.c b/mkprecompiled.c index f9a68ed..d8d11d3 100644 --- a/mkprecompiled.c +++ b/mkprecompiled.c @@ -449,20 +449,20 @@ void encode_uint32(uint32 val, uint8 data[4]) * bytes, and build a uint32. */ -uint32 decode_uint32(uint8 *buf) +uint32 decode_uint32(char *buf) { uint32 ret = 0; - ret += (uint32) buf[3]; + ret += (((uint32) buf[3]) & 0xff); ret <<= 8; - ret += (uint32) buf[2]; + ret += (((uint32) buf[2]) & 0xff); ret <<= 8; - ret += (uint32) buf[1]; + ret += (((uint32) buf[1]) & 0xff); ret <<= 8; - ret += (uint32) buf[0]; + ret += (((uint32) buf[0]) & 0xff); ret <<= 0; return ret; @@ -592,7 +592,7 @@ int pack(Options *op) int unpack(Options *op) { int dst_fd, fd, ret, offset, len = 0; - uint8 *buf, *dst; + char *buf, *dst; uint32 crc, major, minor, patch, val, size; char *description, *proc_version_string; diff --git a/ncurses-ui.c b/ncurses-ui.c index ccdf24a..847ad8f 100644 --- a/ncurses-ui.c +++ b/ncurses-ui.c @@ -136,6 +136,8 @@ typedef struct { #define NV_NCURSES_ENTER 10 #define NV_NCURSES_BACKSPACE 8 +#define NV_NCURSES_CTRL(x) ((x) & 0x1f) + /* * somewhat arbitrary minimum values: if the current window size is @@ -205,7 +207,7 @@ static void nv_ncurses_do_progress_bar_message(DataStruct *, const char *, /* pager functions */ static PagerStruct *nv_ncurses_create_pager(DataStruct *, int, int, int, int, - TextRows *, const char *); + TextRows *, const char *, int); static void nv_ncurses_pager_update(DataStruct *, PagerStruct *); static void nv_ncurses_pager_handle_events(DataStruct *, PagerStruct *, int); static void nv_ncurses_destroy_pager(PagerStruct *); @@ -230,7 +232,7 @@ static void nv_ncurses_free_text_rows(TextRows *); static int nv_ncurses_format_print(DataStruct *, RegionStruct *, int, int, int, int, TextRows *t); -static int nv_ncurses_check_resize(DataStruct *); +static int nv_ncurses_check_resize(DataStruct *, bool); @@ -399,7 +401,7 @@ static char *nv_ncurses_get_input(Options *op, if (!msg) return NULL; - nv_ncurses_check_resize(d); + nv_ncurses_check_resize(d, FALSE); color = d->use_color ? NV_NCURSES_INPUT_COLOR : A_REVERSE; @@ -522,7 +524,7 @@ static char *nv_ncurses_get_input(Options *op, /* wait for input */ - if (nv_ncurses_check_resize(d)) goto draw_get_input; + if (nv_ncurses_check_resize(d, FALSE)) goto draw_get_input; ch = getch(); switch (ch) { @@ -568,6 +570,11 @@ static char *nv_ncurses_get_input(Options *op, redraw = TRUE; } break; + + case NV_NCURSES_CTRL('L'): + nv_ncurses_check_resize(d, TRUE); + goto draw_get_input; + break; } /* @@ -621,7 +628,7 @@ static int nv_ncurses_display_license(Options *op, const char *license) { DataStruct *d = (DataStruct *) op->ui_priv; TextRows *t_pager = NULL; - int ch, x; + int ch, x, cur = 0; int button_width, button_y, accept_x, no_accept_x, accepted; PagerStruct *p = NULL; char *str; @@ -631,7 +638,8 @@ static int nv_ncurses_display_license(Options *op, const char *license) "and continue with the installation, or select " "\"Do Not Accept\" to abort the installation."; - nv_ncurses_check_resize(d); + nv_ncurses_check_resize(d, FALSE); + accepted = FALSE; draw_license: @@ -651,7 +659,6 @@ static int nv_ncurses_display_license(Options *op, const char *license) button_y = d->message->h - 2; accept_x = (d->message->w - (button_width * 3)) / 2; no_accept_x = accept_x + (button_width * 2); - accepted = 0; nv_ncurses_draw_button(d, d->message, accept_x, button_y, button_width, 1, "Accept", accepted, FALSE); @@ -664,7 +671,7 @@ static int nv_ncurses_display_license(Options *op, const char *license) t_pager = d->format_text_rows(NULL, license, d->message->w, TRUE); p = nv_ncurses_create_pager(d, 1, d->message->h + 2, d->message->w, d->height - d->message->h - 4, - t_pager, "NVIDIA Software License"); + t_pager, "NVIDIA Software License", cur); refresh(); /* process key strokes */ @@ -672,7 +679,10 @@ static int nv_ncurses_display_license(Options *op, const char *license) do { /* if a resize occurred, jump back to the top and redraw */ - if (nv_ncurses_check_resize(d)) goto draw_license; + if (nv_ncurses_check_resize(d, FALSE)) { + cur = p->cur; + goto draw_license; + } ch = getch(); switch (ch) { @@ -697,6 +707,12 @@ static int nv_ncurses_display_license(Options *op, const char *license) refresh(); break; + case NV_NCURSES_CTRL('L'): + nv_ncurses_check_resize(d, TRUE); + cur = p->cur; + goto draw_license; + break; + default: break; } @@ -821,8 +837,15 @@ static void nv_ncurses_message(Options *op, int level, const char *msg) do { /* if a resize occurred, jump back to the top and redraw */ - if (nv_ncurses_check_resize(d)) goto draw_message; + if (nv_ncurses_check_resize(d, FALSE)) goto draw_message; ch = getch(); + + switch (ch) { + case NV_NCURSES_CTRL('L'): + nv_ncurses_check_resize(d, TRUE); + goto draw_message; + break; + } } while (ch != NV_NCURSES_ENTER); /* animate the button being pushed down */ @@ -877,7 +900,8 @@ static int nv_ncurses_approve_command_list(Options *op, CommandList *cl, TextRows *t_pager = NULL; PagerStruct *p = NULL; char *str, *question; - int len, ch, x, yes_x, no_x, yes, button_w, button_y; + int button_w, button_y, yes_x, no_x; + int len, ch, x, yes, cur = 0; /* initialize the question string */ @@ -888,7 +912,8 @@ static int nv_ncurses_approve_command_list(Options *op, CommandList *cl, /* check if the window was resized */ - nv_ncurses_check_resize(d); + nv_ncurses_check_resize(d, FALSE); + yes = 1; draw_command_list: @@ -912,8 +937,6 @@ static int nv_ncurses_approve_command_list(Options *op, CommandList *cl, yes_x = (d->message->w - button_w*3)/2 + 0; no_x = (d->message->w - button_w*3)/2 + 2*button_w; - yes = 1; - nv_ncurses_draw_button(d, d->message, yes_x, button_y, button_w, 1, "Yes", yes, FALSE); nv_ncurses_draw_button(d, d->message, no_x, button_y, @@ -924,7 +947,7 @@ static int nv_ncurses_approve_command_list(Options *op, CommandList *cl, t_pager = nv_ncurses_create_command_list_textrows(d, cl, d->message->w); p = nv_ncurses_create_pager(d, 1, d->message->h + 2, d->message->w, d->height - d->message->h - 4, - t_pager, "Proposed Commandlist"); + t_pager, "Proposed Commandlist", cur); refresh(); /* process key strokes */ @@ -932,8 +955,11 @@ static int nv_ncurses_approve_command_list(Options *op, CommandList *cl, do { /* if a resize occurred, jump back to the top and redraw */ - if (nv_ncurses_check_resize(d)) goto draw_command_list; - ch = getch(); + if (nv_ncurses_check_resize(d, FALSE)) { + cur = p->cur; + goto draw_command_list; + } + ch = getch(); switch (ch) { case NV_NCURSES_TAB: @@ -953,6 +979,13 @@ static int nv_ncurses_approve_command_list(Options *op, CommandList *cl, button_w, 1, "No", !yes, FALSE); refresh(); break; + + case NV_NCURSES_CTRL('L'): + nv_ncurses_check_resize(d, TRUE); + cur = p->cur; + goto draw_command_list; + break; + default: break; } @@ -1022,7 +1055,8 @@ static int nv_ncurses_yes_no(Options *op, const int def, const char *msg) /* check if the window was resized */ - nv_ncurses_check_resize(d); + nv_ncurses_check_resize(d, FALSE); + yes = def; draw_yes_no: @@ -1053,8 +1087,6 @@ static int nv_ncurses_yes_no(Options *op, const int def, const char *msg) y = d->message->h - 2; yes_x = (d->message->w - w*3)/2 + 0; no_x = (d->message->w - w*3)/2 + 2*w; - - yes = def; nv_ncurses_draw_button(d, d->message, yes_x, y, w, h, "Yes", yes,FALSE); nv_ncurses_draw_button(d, d->message, no_x, y, w, h, "No", !yes, FALSE); @@ -1064,8 +1096,8 @@ static int nv_ncurses_yes_no(Options *op, const int def, const char *msg) /* process key strokes */ do { - if (nv_ncurses_check_resize(d)) goto draw_yes_no; - ch = getch(); + if (nv_ncurses_check_resize(d, FALSE)) goto draw_yes_no; + ch = getch(); switch (ch) { case NV_NCURSES_TAB: @@ -1085,6 +1117,12 @@ static int nv_ncurses_yes_no(Options *op, const int def, const char *msg) "No", !yes, FALSE); refresh(); break; + + case NV_NCURSES_CTRL('L'): + nv_ncurses_check_resize(d, TRUE); + goto draw_yes_no; + break; + default: break; } @@ -1128,7 +1166,7 @@ static void nv_ncurses_status_begin(Options *op, { DataStruct *d = (DataStruct *) op->ui_priv; - nv_ncurses_check_resize(d); + nv_ncurses_check_resize(d, FALSE); /* cache the progress bar title */ @@ -1144,7 +1182,7 @@ static void nv_ncurses_status_begin(Options *op, d->message->w); refresh(); - + } /* nv_ncurses_status_begin() */ @@ -1157,7 +1195,7 @@ 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; + int i, n, h, ch; int p[4]; char v[4]; DataStruct *d = (DataStruct *) op->ui_priv; @@ -1167,11 +1205,32 @@ static void nv_ncurses_status_update(Options *op, const float percent, * redraw the entire progress bar region. */ - if (nv_ncurses_check_resize(d) || !d->message) { + 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); } - + + /* temporarily set getch() to non-blocking mode */ + + nodelay(stdscr, TRUE); + + while ((ch = getch()) != ERR) { + /* + * if the user explicitely requested that the screen be + * redrawn by pressing CTRL-L, then also redraw the entire + * progress bar egion. + */ + if (ch == NV_NCURSES_CTRL('L')) { + nv_ncurses_check_resize(d, TRUE); + if (d->message) nv_ncurses_destroy_region(d->message); + nv_ncurses_do_progress_bar_region(d); + } + } + + /* set getch() back to blocking mode */ + + nodelay(stdscr, FALSE); + /* compute the percentage */ n = ((int) (percent * (float) (d->message->w - 2))); @@ -1238,7 +1297,7 @@ static void nv_ncurses_status_end(Options *op, const char *msg) * redraw the entire progress bar region. */ - if (nv_ncurses_check_resize(d) || !d->message) { + 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); } @@ -1710,12 +1769,14 @@ static void nv_ncurses_do_progress_bar_message(DataStruct *d, const char *str, * w : width of the pager * h : height of the pager * t : TextRows to be displayed - * label : string to be displayed in the status bar. + * label : string to be displayed in the status bar + * cur : initial current line of the pager */ static PagerStruct *nv_ncurses_create_pager(DataStruct *d, int x, int y, int w, int h, - TextRows *t, const char *label) + TextRows *t, const char *label, + int cur) { PagerStruct *p = (PagerStruct *) malloc(sizeof(PagerStruct)); @@ -1723,7 +1784,7 @@ static PagerStruct *nv_ncurses_create_pager(DataStruct *d, p->region = nv_ncurses_create_region(d, x, y, w, h, A_NORMAL, A_NORMAL); p->label = label; - p->cur = 0; + p->cur = cur; p->page = h - 2; @@ -1808,9 +1869,10 @@ static void nv_ncurses_pager_update(DataStruct *d, PagerStruct *p) static void nv_ncurses_pager_handle_events(DataStruct *d, PagerStruct *p, int ch) { - int n = p->t->n - (p->region->h - 1); - + int n; + if (!p) return; + n = p->t->n - (p->region->h - 1); switch (ch) { case KEY_UP: @@ -2091,20 +2153,22 @@ static int nv_ncurses_format_print(DataStruct *d, RegionStruct *region, * clear everything, update our cached dimensions, and recreate the * header and footer. * - * XXX we could catch the SIGREGIONCH signal, but that's + * XXX we could catch the SIGWINCH (window resize) signal, but that's * asynchronous... it's safer to only attempt to handle a resize when * we know we can. */ -static int nv_ncurses_check_resize(DataStruct *d) +static int nv_ncurses_check_resize(DataStruct *d, bool force) { int x, y; getmaxyx(stdscr, y, x); - if ((x == d->width) && (y == d->height)) { - /* no resize detected... just return */ - return FALSE; + if (!force) { + if ((x == d->width) && (y == d->height)) { + /* no resize detected... just return */ + return FALSE; + } } /* we have been resized */ diff --git a/nvidia-installer.1.m4 b/nvidia-installer.1.m4 new file mode 100644 index 0000000..3354aed --- /dev/null +++ b/nvidia-installer.1.m4 @@ -0,0 +1,115 @@ +dnl This file is to be preprocessed by m4. +changequote([[[, ]]]) +define(__OPTIONS__, [[[include([[[options.1.inc]]])dnl]]])dnl +.\" Copyright (C) 2005 NVIDIA Corporation. +.\" +__HEADER__ +.\" Define the URL macro and then load the URL package if it exists. +.de URL +\\$2 \(laURL: \\$1 \(ra\\$3 +.. +.if \n[.g] .mso www.tmac +.TH nvidia\-installer 1 2005-09-01 "nvidia\-installer __VERSION__" +.SH NAME +nvidia\-installer \- install, upgrade, or uninstall the NVIDIA Accelerated Graphics Driver Set +.SH SYNOPSIS +.B nvidia\-installer +[ +.I options +] +.SH DESCRIPTION +.PP +.B nvidia\-installer +is a tool for installing, updating, and uninstalling the NVIDIA __INSTALLER_OS__ Graphics Driver. +When the driver is installed by running, for example: +.sp +.ti +5 +sh NVIDIA\-__INSTALLER_OS__\-__INSTALLER_ARCH__\-__DRIVER_VERSION__\-pkg1.run +.sp +The .run file unpacks itself and invokes the contained +.B nvidia\-installer +utility. +.B nvidia\-installer +then walks you through the installation process. +As part of installation, +.B nvidia\-installer +is installed on the system for later use, such as for uninstalling the currently installed driver or updating to newer drivers. +.PP +In the default 'install' mode of operation, +.B nvidia\-installer +probes your system to determine which driver files should be installed and where. +.B nvidia\-installer +then determines which files already present on your system will conflict with driver installation; those files are noted and will be later backed up. +At this point, nothing will have been changed on the file system, though a "command list" will have been generated. +If running in expert mode (requested with the +.B \-\-expert +commandline option), this command list will be presented so that you can review all operations that +.B nvidia\-installer +intends to perform. +Finally, +.B nvidia\-installer +executes the commandlist, backing up conflicting files already present on the file system, installing the new driver files on the file system, creating symlinks, and running system utilities like +.BR depmod (8) +and +.BR ldconfig (8). +.PP +To later uninstall the NVIDIA __INSTALLER_OS__ graphics driver, you can run +.B nvidia\-installer \-\-uninstall. +In the 'uninstall' mode of operation, all driver files that were installed on the system are deleted, and all files that were backed up during installation are restored to their original locations. +The uninstall process should restore your filesystem to its state prior to installation. +If you install one NVIDIA __INSTALLER_OS__ graphics driver while another is already installed, this uninstall step is automatically performed on the old driver at the beginning of installation of the new driver. +.PP +You can also use +.B nvidia\-installer +to automatically update to newer drivers. +.PP +You can query the latest driver available on NVIDIA's website with the +.B \-\-latest +option, or request that the latest driver, if newer than your current driver, be automatically downloaded and installed by specifying the +.B \-\-update +commandline option. +.PP +\fBnvidia\-installer\fR's backend is separate from its user interface; the installer will use an ncurses-based user interface if it can find the correct ncurses library, otherwise, it will fall back to a simple commandline user interface. +To disable use of the ncurses user interface, use the option +.B \-\-ui=none. +Additional user interfaces, utilizing GTK+ or QT, for example, could be provided in the future. +.\" XXX should we describe precompiled kernel interfaces here? +.PP +The source code to +.B nvidia\-installer +is released under the GPL and available here: +.sp +.ti +5 +.URL "ftp://download.nvidia.com/XFree86/nvidia\-installer/" +.sp +Patches are welcome. +dnl Call gen-manpage-opts to generate this section. +__OPTIONS__ +.SH EXAMPLES +.TP +.B nvidia\-installer \-\-latest +Connect to NVIDIA's FTP site, and report the latest driver version and the URL to the latest driver file. +.TP +.B nvidia\-installer \-\-update +Connect to NVIDIA's FTP site. +If a newer version of the driver is available, download and install it. +Use +.B \-\-force\-update +to install the most recent driver even if +.B \-\-nvidia\-installer +detects that it is installed already. +.TP +.B nvidia\-installer \-\-uninstall +Remove the NVIDIA driver and restore files that were overwritten during the install process. +.\" .SH FILES +.\" .I /usr/lib/libGL.so.NNNN +.SH AUTHOR +Aaron Plattner +.br +NVIDIA Corporation +.SH "SEE ALSO" +.BR nvidia-xconfig (1), +.BR nvidia-settings (1), +.I /usr/share/doc/NVIDIA_GLX-1.0/README.txt +.SH COPYRIGHT +Copyright \(co 2005 NVIDIA Corporation. diff --git a/nvidia-installer.c b/nvidia-installer.c index 75c4a8d..6645622 100644 --- a/nvidia-installer.c +++ b/nvidia-installer.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -49,14 +50,14 @@ #include "update.h" #include "format.h" #include "sanity.h" +#include "option_table.h" #define TAB " " +#define BIGTAB " " static void print_version(void); -static void print_help(void); -static void print_advanced_options(void); -static void print_help_args_only(int args_only); -static void print_advanced_options_args_only(int args_only); +static void print_help(int advanced); +static void print_help_args_only(int args_only, int advanced); @@ -81,26 +82,40 @@ static void print_version(void) } - /* - * print_help() - print usage information + * cook_description() - the description string may contain text within + * brackets, which is used by the manpage generator to denote text to + * be italicized. We want to omit the bracket characters here. */ -static void print_help(void) +static char *cook_description(const char *description) { - print_version(); + int len; + char *s, *dst; + const char *src; - fmtout(""); - fmtout("nvidia-installer [options]"); - fmtout(""); + len = strlen(description); + s = nvalloc(len + 1); - print_help_args_only(FALSE); + for (src = description, dst = s; *src; src++) { + if (*src != '[' && (*src != ']')) { + *dst = *src; + dst++; + } + } -} /* print_help() */ + *dst = '\0'; + + return s; + +} /* cook_description() */ +/* + * print_help() - print usage information + */ -static void print_advanced_options(void) +static void print_help(int advanced) { print_version(); @@ -108,68 +123,16 @@ static void print_advanced_options(void) fmtout("nvidia-installer [options]"); fmtout(""); - fmtout(""); - fmtout("COMMON OPTIONS:"); - fmtout(""); - - print_help_args_only(FALSE); - - fmtout(""); - fmtout("ADVANCED OPTIONS:"); - fmtout(""); - - print_advanced_options_args_only(FALSE); - -} /* print_advanced_options() */ - - - -static void print_help_args_only(int args_only) -{ - /* - * the args_only parameter is used by makeself.sh to get our - * argument list and description; in this case we don't want to - * format to the width of the terminal, so hardcode the width to - * 65. - */ - - if (args_only) reset_current_terminal_width(65); - - fmtout("-a, --accept-license"); - fmtoutp(TAB, "Bypass the display and prompting for acceptance of the " - "NVIDIA Software License Agreement. By passing this option to " - "nvidia-installer, you indicate that you have read and accept the " - "License Agreement contained in the file 'LICENSE' (in the top " - "level directory of the driver package)."); - fmtout(""); - - fmtout("--update"); - fmtoutp(TAB, "Connect to the NVIDIA ftp server '%s' and determine the " - "latest available driver version. If there is a more recent " - "driver available, automatically download and install it. Any " - "other options given on the commandline will be passed on to the " - "downloaded driver package when installing it.", DEFAULT_FTP_SITE); - fmtout(""); + print_help_args_only(FALSE, advanced); - fmtout("-v, --version"); - fmtoutp(TAB, "Print the nvidia-installer version and exit."); - fmtout(""); - - fmtout("-h, --help"); - fmtoutp(TAB, "Print usage information for the common commandline options " - "and exit."); - fmtout(""); - - fmtout("-A, --advanced-options"); - fmtoutp(TAB, "Print usage information for the common commandline options " - "as well as the advanced options, and then exit."); - fmtout(""); - -} /* print_help_args_only() */ +} /* print_help() */ -static void print_advanced_options_args_only(int args_only) +static void print_help_args_only(int args_only, int advanced) { + int i, j, len; + char *msg, *tmp, scratch[64]; + const NVOption *o; /* * the args_only parameter is used by makeself.sh to get our * argument list and description; in this case we don't want to @@ -179,268 +142,45 @@ static void print_advanced_options_args_only(int args_only) if (args_only) reset_current_terminal_width(65); - fmtout("-i, --driver-info"); - fmtoutp(TAB, "Print information about the currently installed NVIDIA " - "driver version."); - fmtout(""); - - fmtout("--uninstall"); - fmtoutp(TAB, "Uninstall the currently installed NVIDIA driver."); - fmtout(""); - - fmtout("--sanity"); - fmtoutp(TAB, "Perform basic sanity tests on an existing NVIDIA " - "driver installation."); - fmtout(""); - - fmtout("-e, --expert"); - fmtoutp(TAB, "Enable 'expert' installation mode; more detailed questions " - "will be asked, and more verbose output will be printed; " - "intended for expert users. The questions may be suppressed " - "with the '--no-questions' commandline option."); - fmtout(""); - - fmtout("-q, --no-questions"); - fmtoutp(TAB, "Do not ask any questions; the default (normally 'yes') " - "is assumed for " - "all yes/no questions, and the default string is assumed in " - "any situation where the user is prompted for string input. " - "The one question that is not bypassed by this option is " - "license acceptance; the license may be accepted with the " - "commandline option '--accept-license'."); - fmtout(""); + for (i = 0; __options[i].name; i++) { + o = &__options[i]; - fmtout("-s, --silent"); - fmtoutp(TAB, "Run silently; no questions are asked and no output is " - "printed, except for error messages to stderr. This option " - "implies '--ui=none --no-questions --accept-license'."); - fmtout(""); + /* + * if non-advanced help is requested, and the ALWAYS flag is + * not set, then skip this option + */ - fmtout("--x-prefix=[X PREFIX]"); - fmtoutp(TAB, "The prefix under which the X components of the " - "NVIDIA driver will be installed; the default is: '%s'. Only " - "under rare circumstances should this option be used.", - DEFAULT_XFREE86_INSTALLATION_PREFIX); - fmtout(""); - - fmtout("--opengl-prefix=[OPENGL PREFIX]"); - fmtoutp(TAB, "The prefix under which the OpenGL components of the " - "NVIDIA driver will be installed; the default is: '%s'. Only ", - "under rare circumstances should this option be used. The Linux " - "OpenGL ABI (http://oss.sgi.com/projects/ogl-sample/ABI/) " - "mandates this default value.", - DEFAULT_OPENGL_INSTALLATION_PREFIX); - fmtout(""); - -#if defined(NV_X86_64) - fmtout("--compat32-prefix=[COMPAT32 PREFIX]"); - fmtoutp(TAB, "The path relative to which the 32bit compatibility " - "libraries will be installed on x86-64 systems; this option " - "is unset by default, the OpenGL prefix alone determines " - "the target location. Only under very rare circumstances " - "should this option need to be used."); - fmtout(""); -#endif /* NV_X86_64 */ - - fmtout("--installer-prefix=[INSTALLER PREFIX]"); - fmtoutp(TAB, "The prefix under which the installer binary will be " - "installed; the default is: '%s'. Note: use the " - "\"--utility-prefix\" option instead.", - DEFAULT_INSTALLER_INSTALLATION_PREFIX); - fmtout(""); - - fmtout("--utility-prefix=[UTILITY PREFIX]"); - fmtoutp(TAB, "The prefix under which the various NVIDIA utilities " - "(nvidia-installer, nvidia-settings, nvidia-bug-report.sh) will " - "be installed; the default is: '%s'.", - DEFAULT_UTILITY_INSTALLATION_PREFIX); - fmtout(""); + if (!advanced && !(o->flags & OPTION_HELP_ALWAYS)) continue; - fmtout("--kernel-include-path=[KERNEL INCLUDE PATH]"); - fmtoutp(TAB, "The directory containing the kernel include files that " - "should be used when compiling the NVIDIA kernel module. " - "This option is deprecated; please use '--kernel-source-path' " - "instead."); - fmtout(""); - - fmtout("--kernel-source-path=[KERNEL SOURCE PATH]"); - fmtoutp(TAB, "The directory containing the kernel source files that " - "should be used when compiling the NVIDIA kernel module. " - "When not specified, the installer will use " - "'/lib/modules/`uname -r`/build', if that " - "directory exists. Otherwise, it will use " - "'/usr/src/linux'."); - fmtout(""); + /* Skip options with no help text */ + if (!o->description) continue; - fmtout("--kernel-output-path=[KERNEL OUTPUT PATH]"); - fmtoutp(TAB, "The directory containing any KBUILD output files if " - "either one of the 'KBUILD_OUTPUT' or 'O' parameters were " - "passed to KBUILD when building the kernel image/modules. " - "When not specified, the installer will assume that no " - "separate output directory was used."); - fmtout(""); - - fmtout("--kernel-install-path=[KERNEL INSTALL PATH]"); - fmtoutp(TAB, "The directory in which the NVIDIA kernel module should be " - "installed. The default value is either '/lib/modules/`uname " - "-r`/kernel/drivers/video' (if '/lib/modules/`uname -r`/kernel' " - "exists) or '/lib/modules/`uname -r`/video'."); - fmtout(""); - - fmtout("--proc-mount-point=[PROC FILESYSTEM MOUNT POINT]"); - fmtoutp(TAB, "The mount point for the proc file system; if not " - "specified, then this value defaults to '%s' (which is normally " - "correct). The mount point of the proc filesystem is needed " - "because the contents of '/version' is used when " - "identifying if a precompiled kernel interface is available for " - "the currently running kernel. This option should only be needed " - "in very rare circumstances.", DEFAULT_PROC_MOUNT_POINT); - fmtout(""); - - fmtout("--log-file-name=[LOG FILE NAME]"); - fmtoutp(TAB, "File name of the installation log file (the default is: " - "'%s').", DEFAULT_LOG_FILE_NAME); - fmtout(""); - - fmtout("--tmpdir=[TMPDIR]"); - fmtoutp(TAB, "Use the specified directory as a temporary directory when " - "downloading files from the NVIDIA ftp site; " - "if not given, then the following list will be searched, and " - "the first one that exists will be used: $TMPDIR, /tmp, ., " - "$HOME."); - fmtout(""); - - fmtout("-m, --ftp-mirror=[FTP MIRROR]"); - fmtoutp(TAB, "Use the specified ftp mirror rather than the default '%s' " - "when downloading driver updates.", DEFAULT_FTP_SITE); - fmtout(""); - - fmtout("-l, --latest"); - fmtoutp(TAB, "Connect to the NVIDIA ftp server %s (or use the ftp mirror " - "specified with the '--ftp-mirror' option) and query the most " - "recent %s-%s driver version number.", DEFAULT_FTP_SITE, - INSTALLER_OS, INSTALLER_ARCH); - fmtout(""); - - fmtout("-f, --force-update"); - fmtoutp(TAB, "Forces an update to proceed, even if the installer " - "thinks the latest driver is already installed; this option " - "implies '--update'."); - fmtout(""); - - fmtout("--ui=[USER INTERFACE]"); - fmtoutp(TAB, "Specify what user interface to use, if available. " - "Valid values are 'ncurses' (the default) or 'none'. " - "If the ncurses interface fails to initialize, or 'none' " - "is specified, then a simple printf/scanf interface will " - "be used."); - fmtout(""); - - fmtout("-c, --no-ncurses-color"); - fmtoutp(TAB, "Disable use of color in the ncurses user interface."); - fmtout(""); - - fmtout("--opengl-headers"); - fmtoutp(TAB, "Normally, installation does not install NVIDIA's OpenGL " - "header files. This option enables installation of the NVIDIA " - "OpenGL header files."); - fmtout(""); - - fmtout("--force-tls=[TLS TYPE]"); - fmtoutp(TAB, "NVIDIA's OpenGL libraries are compiled with one of two " - "different thread local storage (TLS) mechanisms: 'classic tls' " - "which is used on systems with glibc 2.2 or older, and 'new tls' " - "which is used on systems with tls-enabled glibc 2.3 or newer. " - "The nvidia-installer will select the OpenGL " - "libraries appropriate for your system; however, you may use " - "this option to force the installer to install one library " - "type or another. Valid values for [TLS TYPE] are 'new' and " - "'classic'."); - fmtout(""); - -#if defined(NV_X86_64) - fmtout("--force-tls-compat32=[TLS TYPE]"); - fmtoutp(TAB, "This option forces the installer to install a specific " - "32bit compatibility OpenGL TLS library; further details " - "can be found in the description of the '--force-tls' option."); - fmtout(""); -#endif /* NV_X86_64 */ - - fmtout("-k, --kernel-name=[KERNELNAME]"); - fmtoutp(TAB, "Build and install the NVIDIA kernel module for the " - "non-running kernel specified by [KERNELNAME] ([KERNELNAME] " - "should be the output of `uname -r` when the target kernel is " - "actually running). This option implies " - "'--no-precompiled-interface'. If the options " - "'--kernel-install-path' and '--kernel-source-path' are not " - "given, then they will be inferred from [KERNELNAME]; eg: " - "'/lib/modules/[KERNELNAME]/kernel/drivers/video/' and " - "'/lib/modules/[KERNELNAME]/build/', respectively."); - fmtout(""); - - fmtout("-n, --no-precompiled-interface"); - fmtoutp(TAB, "Disable use of precompiled kernel interfaces."); - fmtout(""); - - fmtout("--no-runlevel-check"); - fmtoutp(TAB, "Normally, the installer checks the current runlevel and " - "warns users if they are in runlevel 1: in runlevel 1, some " - "services that are normally active are disabled (such as devfs), " - "making it difficult for the installer to properly setup the " - "kernel module configuration files. This option disables the " - "runlevel check."); - fmtout(""); - - fmtout("--no-abi-note"); - fmtoutp(TAB, "The NVIDIA OpenGL libraries contain an OS ABI note tag, " - "which identifies the minimum kernel version needed to use the " - "library. This option causes the installer to remove this note " - "from the OpenGL libraries during installation."); - fmtout(""); - - fmtout("--no-rpms"); - fmtoutp(TAB, "Normally, the installer will check for several rpms that " - "conflict with the driver (specifically: NVIDIA_GLX and " - "NVIDIA_kernel), and remove them if present. This option " - "disables this check."); - fmtout(""); - - fmtout("-b, --no-backup"); - fmtoutp(TAB, "During driver installation, conflicting files are backed " - "up, so that they can be restored when the driver is " - "uninstalled. This option causes the installer to simply delete " - "conflicting files, rather than back them up."); - fmtout(""); - - fmtout("--no-network"); - fmtoutp(TAB, "This option instructs the installer to not attempt to " - "connect to the NVIDIA ftp site (for updated precompiled kernel " - "interfaces, for example)."); - fmtout(""); - - fmtout("--no-recursion"); - fmtoutp(TAB, "Normally, nvidia-installer will recursively search for " - "potentially conflicting libraries under the default OpenGL " - "and X server installation locations. With this option set, " - "the installer will only search in the top-level directories."); - fmtout(""); - - fmtout("-K, --kernel-module-only"); - fmtoutp(TAB, "Install a kernel module only, and don't uninstall the " - "existing driver. This is intended to be used to install kernel " - "modules for additional kernels (in cases where you might boot " - "between several different kernels). To use this option, you " - "must already have a driver installed, and the version of the " - "installed driver must match the version of this kernel " - "module."); - fmtout(""); - - fmtout("--precompiled-kernel-interfaces-path"); - fmtoutp(TAB, "Before searching for a precompiled kernel interface in the " - ".run file, search in the specified directory."); - fmtout(""); - -} /* print_advanced_options_args_only() */ + if (o->flags & NVOPT_IS_BOOLEAN) { + msg = nvstrcat("--", o->name, "/--no-", o->name, NULL); + } else if (isalnum(o->val)) { + sprintf(scratch, "%c", o->val); + msg = nvstrcat("-", scratch, ", --", o->name, NULL); + } else { + msg = nvstrcat("--", o->name, NULL); + } + if (o->flags & NVOPT_HAS_ARGUMENT) { + len = strlen(o->name); + for (j = 0; j < len; j++) scratch[j] = toupper(o->name[j]); + scratch[len] = '\0'; + tmp = nvstrcat(msg, "=", scratch, NULL); + nvfree(msg); + msg = tmp; + } + fmtoutp(TAB, msg); + if (o->description) { + tmp = cook_description(o->description); + fmtoutp(BIGTAB, tmp); + free(tmp); + } + fmtout(""); + nvfree(msg); + } +} /* print_help_args_only() */ /* @@ -462,90 +202,35 @@ Options *parse_commandline(int argc, char *argv[]) Options *op; int c, option_index = 0; -#define XFREE86_PREFIX_OPTION 1 -#define OPENGL_PREFIX_OPTION 2 -#define KERNEL_INCLUDE_PATH_OPTION 3 -#define KERNEL_INSTALL_PATH_OPTION 4 -#define UNINSTALL_OPTION 5 -#define PROC_MOUNT_POINT_OPTION 6 -#define USER_INTERFACE_OPTION 7 -#define LOG_FILE_NAME_OPTION 8 -#define HELP_ARGS_ONLY_OPTION 9 -#define TMPDIR_OPTION 10 -#define OPENGL_HEADERS_OPTION 11 -#define INSTALLER_PREFIX_OPTION 12 -#define FORCE_TLS_OPTION 13 -#define SANITY_OPTION 14 -#define ADVANCED_OPTIONS_ARGS_ONLY_OPTION 15 -#define UTILITY_PREFIX_OPTION 16 -#define ADD_THIS_KERNEL_OPTION 17 -#define RPM_FILE_LIST_OPTION 18 -#define NO_RUNLEVEL_CHECK_OPTION 19 -#define NO_NETWORK_OPTION 20 -#define PRECOMPILED_KERNEL_INTERFACES_PATH 21 -#define NO_ABI_NOTE_OPTION 22 -#define KERNEL_SOURCE_PATH_OPTION 23 -#define NO_RPMS_OPTION 24 -#define X_PREFIX_OPTION 25 -#define KERNEL_OUTPUT_PATH_OPTION 26 -#define NO_RECURSION_OPTION 27 -#define FORCE_TLS_COMPAT32_OPTION 28 -#define COMPAT32_PREFIX_OPTION 29 - - - static struct option long_options[] = { - { "accept-license", 0, NULL, 'a' }, - { "update", 0, NULL, 'u' }, - { "force-update", 0, NULL, 'f' }, - { "expert", 0, NULL, 'e' }, - { "version", 0, NULL, 'v' }, - { "debug", 0, NULL, 'd' }, - { "driver-info", 0, NULL, 'i' }, - { "no-precompiled-interface", 0, NULL, 'n' }, - { "no-ncurses-color", 0, NULL, 'c' }, - { "latest", 0, NULL, 'l' }, - { "ftp-mirror", 1, NULL, 'm' }, - { "no-questions", 0, NULL, 'q' }, - { "kernel-name", 1, NULL, 'k' }, - { "silent", 0, NULL, 's' }, - { "help", 0, NULL, 'h' }, - { "advanced-options", 0, NULL, 'A' }, - { "no-backup", 0, NULL, 'b' }, - { "kernel-module-only", 0, NULL, 'K' }, - { "xfree86-prefix", 1, NULL, XFREE86_PREFIX_OPTION }, - { "x-prefix", 1, NULL, X_PREFIX_OPTION }, - { "compat32-prefix", 1, NULL, COMPAT32_PREFIX_OPTION }, - { "opengl-prefix", 1, NULL, OPENGL_PREFIX_OPTION }, - { "installer-prefix", 1, NULL, INSTALLER_PREFIX_OPTION }, - { "utility-prefix", 1, NULL, UTILITY_PREFIX_OPTION }, - { "kernel-include-path", 1, NULL, KERNEL_INCLUDE_PATH_OPTION }, - { "kernel-source-path", 1, NULL, KERNEL_SOURCE_PATH_OPTION }, - { "kernel-output-path", 1, NULL, KERNEL_OUTPUT_PATH_OPTION }, - { "kernel-install-path", 1, NULL, KERNEL_INSTALL_PATH_OPTION }, - { "uninstall", 0, NULL, UNINSTALL_OPTION }, - { "proc-mount-point", 1, NULL, PROC_MOUNT_POINT_OPTION }, - { "ui", 1, NULL, USER_INTERFACE_OPTION }, - { "log-file-name", 1, NULL, LOG_FILE_NAME_OPTION }, - { "help-args-only", 0, NULL, HELP_ARGS_ONLY_OPTION }, - { "tmpdir", 1, NULL, TMPDIR_OPTION }, - { "opengl-headers", 0, NULL, OPENGL_HEADERS_OPTION }, - { "force-tls", 1, NULL, FORCE_TLS_OPTION }, - { "force-tls-compat32", 1, NULL, FORCE_TLS_COMPAT32_OPTION }, - { "sanity", 0, NULL, SANITY_OPTION }, - { "add-this-kernel", 0, NULL, ADD_THIS_KERNEL_OPTION }, - { "rpm-file-list", 1, NULL, RPM_FILE_LIST_OPTION }, - { "no-runlevel-check", 0, NULL, NO_RUNLEVEL_CHECK_OPTION }, - { "no-network", 0, NULL, NO_NETWORK_OPTION }, - { "no-abi-note", 0, NULL, NO_ABI_NOTE_OPTION }, - { "no-rpms", 0, NULL, NO_RPMS_OPTION }, - { "no-recursion", 0, NULL, NO_RECURSION_OPTION }, - { "precompiled-kernel-interfaces-path", 1, NULL, - PRECOMPILED_KERNEL_INTERFACES_PATH }, - { "advanced-options-args-only", 0, NULL, - ADVANCED_OPTIONS_ARGS_ONLY_OPTION }, - { 0, 0, NULL, 0 } - }; - + const int num_opts = sizeof(__options) / sizeof(__options[0]) - 1; + /* Allocate space for the long options. */ + struct option *long_options = nvalloc(num_opts * sizeof(struct option)); + /* Allocate space for the short options: leave enough room for a letter and + * ':' for each option, plus the '\0'. */ + char *short_options = nvalloc(num_opts * 2 + 1); + char *pShort = short_options; + + /* Generate the table for getopt_long and the string for the short options. */ + for (c = 0; c < num_opts; c++) { + struct option* op = &long_options[c]; + const NVOption* o = &__options[c]; + + op->name = o->name; + op->has_arg = + (o->flags & NVOPT_HAS_ARGUMENT) ? + required_argument : no_argument; + op->flag = NULL; + op->val = o->val; + + if (isalnum(o->val)) { + *pShort++ = o->val; + + if (o->flags & NVOPT_HAS_ARGUMENT) + *pShort++ = ':'; + } + } + *pShort = '\0'; + op = (Options *) nvalloc(sizeof(Options)); /* statically initialized strings */ @@ -566,10 +251,14 @@ Options *parse_commandline(int argc, char *argv[]) #endif op->logging = TRUE; /* log by default */ + op->opengl_headers = TRUE; /* We now install our GL headers by default */ + op->selinux_option = SELINUX_DEFAULT; + + op->sigwinch_workaround = TRUE; while (1) { - c = getopt_long(argc, argv, "afg:evdinclm:qk:shAbK", + c = getopt_long(argc, argv, short_options, long_options, &option_index); if (c == -1) break; @@ -577,7 +266,7 @@ Options *parse_commandline(int argc, char *argv[]) switch (c) { case 'a': op->accept_license = TRUE; break; - case 'u': op->update = TRUE; break; + case UPDATE_OPTION: op->update = TRUE; break; case 'e': op->expert = TRUE; break; case 'v': print_version(); exit(0); break; case 'd': op->debug = TRUE; break; @@ -591,11 +280,14 @@ Options *parse_commandline(int argc, char *argv[]) case 'l': op->latest = TRUE; break; case 'm': op->ftp_site = optarg; break; case 'f': op->update = op->force_update = TRUE; break; - case 'h': print_help(); exit(0); break; - case 'A': print_advanced_options(); exit(0); break; + case 'h': print_help(FALSE); exit(0); break; + case 'A': print_help(TRUE); exit(0); break; case 'q': op->no_questions = TRUE; break; case 'b': op->no_backup = TRUE; break; - case 'K': op->kernel_module_only = TRUE; break; + case 'K': + op->kernel_module_only = TRUE; + op->no_kernel_module = FALSE; /* conflicts */ + break; case 's': op->silent = op->no_questions = op->accept_license = TRUE; op->ui_str = "none"; @@ -609,6 +301,8 @@ Options *parse_commandline(int argc, char *argv[]) case XFREE86_PREFIX_OPTION: case X_PREFIX_OPTION: op->xfree86_prefix = optarg; break; + case X_MODULE_PATH_OPTION: + op->x_module_path = optarg; break; case OPENGL_PREFIX_OPTION: op->opengl_prefix = optarg; break; case COMPAT32_PREFIX_OPTION: @@ -634,11 +328,11 @@ Options *parse_commandline(int argc, char *argv[]) case LOG_FILE_NAME_OPTION: op->log_file_name = optarg; break; case HELP_ARGS_ONLY_OPTION: - print_help_args_only(TRUE); exit(0); break; + print_help_args_only(TRUE, FALSE); exit(0); break; case TMPDIR_OPTION: op->tmpdir = optarg; break; - case OPENGL_HEADERS_OPTION: - op->opengl_headers = TRUE; break; + case NO_OPENGL_HEADERS_OPTION: + op->opengl_headers = FALSE; break; case FORCE_TLS_OPTION: if (strcasecmp(optarg, "new") == 0) op->which_tls = FORCE_NEW_TLS; @@ -673,7 +367,7 @@ Options *parse_commandline(int argc, char *argv[]) op->add_this_kernel = TRUE; break; case ADVANCED_OPTIONS_ARGS_ONLY_OPTION: - print_advanced_options_args_only(TRUE); exit(0); + print_help_args_only(TRUE, TRUE); exit(0); break; case RPM_FILE_LIST_OPTION: op->rpm_file_list = optarg; @@ -681,10 +375,10 @@ Options *parse_commandline(int argc, char *argv[]) case NO_RUNLEVEL_CHECK_OPTION: op->no_runlevel_check = TRUE; break; - case NO_NETWORK_OPTION: + case 'N': op->no_network = TRUE; break; - case PRECOMPILED_KERNEL_INTERFACES_PATH: + case PRECOMPILED_KERNEL_INTERFACES_PATH_OPTION: op->precompiled_kernel_interfaces_path = optarg; break; case NO_ABI_NOTE_OPTION: @@ -696,7 +390,28 @@ Options *parse_commandline(int argc, char *argv[]) case NO_RECURSION_OPTION: op->no_recursion = TRUE; break; - + case FORCE_SELINUX_OPTION: + if (strcasecmp(optarg, "yes") == 0) + op->selinux_option = SELINUX_FORCE_YES; + else if (strcasecmp(optarg, "no") == 0) + op->selinux_option = SELINUX_FORCE_NO; + else if (strcasecmp(optarg, "default")) { + fmterr(""); + fmterr("Invalid parameter for '--force-selinux'; " + "please run `%s --help` for usage information.", + argv[0]); + fmterr(""); + exit(1); + } + break; + case NO_SIGWINCH_WORKAROUND_OPTION: + op->sigwinch_workaround = FALSE; + break; + case NO_KERNEL_MODULE_OPTION: + op->no_kernel_module = TRUE; + op->kernel_module_only = FALSE; /* conflicts */ + break; + default: fmterr(""); fmterr("Invalid commandline, please run `%s --help` " @@ -705,11 +420,26 @@ Options *parse_commandline(int argc, char *argv[]) exit(1); } - op->update_arguments = append_update_arguments(op->update_arguments, - c, optarg, - long_options); - } + /* + * as we go, build a list of options that we would pass on to + * a new invocation of the installer if we were to download a + * new driver and run its installer (update mode). Be sure + * not to place "--update" or "--force-update" in the update + * argument list (avoid infinite loop) + */ + if ((c != UPDATE_OPTION) && (c != 'f')) { + + op->update_arguments = + append_update_arguments(op->update_arguments, + c, optarg, + long_options); + } + } + + nvfree((void*)long_options); + nvfree((void*)short_options); + if (optind < argc) { fmterr(""); fmterr("Unrecognized arguments:"); @@ -780,6 +510,7 @@ int main(int argc, char *argv[]) if (!find_system_utils(op)) goto done; if (!find_module_utils(op)) goto done; + if (!check_selinux(op)) goto done; /* get the latest available driver version */ diff --git a/nvidia-installer.h b/nvidia-installer.h index 7914377..65c4ae0 100644 --- a/nvidia-installer.h +++ b/nvidia-installer.h @@ -49,6 +49,13 @@ typedef enum { MAX_SYSTEM_UTILS } SystemUtils; +typedef enum { + CHCON = MAX_SYSTEM_UTILS, + SELINUX_ENABLED, + GETENFORCE, + MAX_SYSTEM_OPTIONAL_UTILS +} SystemOptionalUtils; + /* * Enumerated type, listing each of the module utilities we'll need. * Keep this enum in sync with the needed_utils string array in @@ -56,7 +63,7 @@ typedef enum { */ typedef enum { - INSMOD = MAX_SYSTEM_UTILS, + INSMOD = MAX_SYSTEM_OPTIONAL_UTILS, MODPROBE, RMMOD, LSMOD, @@ -74,6 +81,8 @@ typedef enum { SUSE, UNITED_LINUX, DEBIAN, + UBUNTU, + GENTOO, OTHER } Distribution; @@ -114,11 +123,16 @@ typedef struct __options { int no_backup; int no_network; int kernel_module_only; + int no_kernel_module; int no_abi_note; int no_rpms; int no_recursion; + int selinux_option; + int selinux_enabled; + int sigwinch_workaround; char *xfree86_prefix; + char *x_module_path; char *opengl_prefix; char *compat32_prefix; char *installer_prefix; @@ -240,73 +254,103 @@ typedef struct { /* file types */ -#define FILE_TYPE_MASK 0x0000ffff - -#define FILE_TYPE_KERNEL_MODULE_SRC 0x00000001 -#define FILE_TYPE_KERNEL_MODULE_CMD 0x00000002 -#define FILE_TYPE_OPENGL_HEADER 0x00000004 -#define FILE_TYPE_OPENGL_LIB 0x00000008 -#define FILE_TYPE_XFREE86_LIB 0x00000010 -#define FILE_TYPE_DOCUMENTATION 0x00000020 -#define FILE_TYPE_OPENGL_SYMLINK 0x00000040 -#define FILE_TYPE_XFREE86_SYMLINK 0x00000080 -#define FILE_TYPE_KERNEL_MODULE 0x00000100 -#define FILE_TYPE_INSTALLER_BINARY 0x00000200 -#define FILE_TYPE_UTILITY_BINARY 0x00000400 -#define FILE_TYPE_LIBGL_LA 0x00000800 -#define FILE_TYPE_TLS_LIB 0x00001000 -#define FILE_TYPE_TLS_SYMLINK 0x00002000 +#define FILE_TYPE_MASK 0x00ffffff + +#define FILE_TYPE_KERNEL_MODULE_SRC 0x00000001 +#define FILE_TYPE_KERNEL_MODULE_CMD 0x00000002 +#define FILE_TYPE_OPENGL_HEADER 0x00000004 +#define FILE_TYPE_OPENGL_LIB 0x00000008 +#define FILE_TYPE_XLIB_STATIC_LIB 0x00000010 +#define FILE_TYPE_XLIB_SHARED_LIB 0x00000020 +#define FILE_TYPE_DOCUMENTATION 0x00000040 +#define FILE_TYPE_OPENGL_SYMLINK 0x00000080 +#define FILE_TYPE_XLIB_SYMLINK 0x00000100 +#define FILE_TYPE_KERNEL_MODULE 0x00000200 +#define FILE_TYPE_INSTALLER_BINARY 0x00000400 +#define FILE_TYPE_UTILITY_BINARY 0x00000800 +#define FILE_TYPE_LIBGL_LA 0x00001000 +#define FILE_TYPE_TLS_LIB 0x00002000 +#define FILE_TYPE_TLS_SYMLINK 0x00004000 +#define FILE_TYPE_UTILITY_LIB 0x00008000 +#define FILE_TYPE_DOT_DESKTOP 0x00010000 +#define FILE_TYPE_UTILITY_SYMLINK 0x00020000 +#define FILE_TYPE_XMODULE_STATIC_LIB 0x00040000 +#define FILE_TYPE_XMODULE_SHARED_LIB 0x00080000 +#define FILE_TYPE_XMODULE_SYMLINK 0x00100000 /* file class: this is used to distinguish OpenGL libraries */ -#define FILE_CLASS_MASK 0xffff0000 - -#define FILE_CLASS_NEW_TLS 0x00010000 -#define FILE_CLASS_CLASSIC_TLS 0x00020000 -#define FILE_CLASS_NATIVE 0x00040000 -#define FILE_CLASS_COMPAT32 0x00080000 - - -#define FILE_TYPE_INSTALLABLE_FILE (FILE_TYPE_OPENGL_LIB | \ - FILE_TYPE_XFREE86_LIB | \ - FILE_TYPE_TLS_LIB | \ - FILE_TYPE_DOCUMENTATION | \ - FILE_TYPE_OPENGL_HEADER | \ - FILE_TYPE_KERNEL_MODULE | \ - FILE_TYPE_INSTALLER_BINARY | \ - FILE_TYPE_UTILITY_BINARY | \ - FILE_TYPE_LIBGL_LA) - -#define FILE_TYPE_HAVE_PATH (FILE_TYPE_OPENGL_LIB | \ - FILE_TYPE_OPENGL_SYMLINK | \ - FILE_TYPE_LIBGL_LA | \ - FILE_TYPE_XFREE86_LIB | \ - FILE_TYPE_XFREE86_SYMLINK | \ - FILE_TYPE_TLS_LIB | \ - FILE_TYPE_TLS_SYMLINK | \ +#define FILE_CLASS_MASK 0xff000000 + +#define FILE_CLASS_NEW_TLS 0x01000000 +#define FILE_CLASS_CLASSIC_TLS 0x02000000 +#define FILE_CLASS_NATIVE 0x04000000 +#define FILE_CLASS_COMPAT32 0x08000000 + +#define FILE_TYPE_XLIB_LIB (FILE_TYPE_XLIB_STATIC_LIB | \ + FILE_TYPE_XLIB_SHARED_LIB) + +#define FILE_TYPE_XMODULE_LIB (FILE_TYPE_XMODULE_STATIC_LIB | \ + FILE_TYPE_XMODULE_SHARED_LIB) + +#define FILE_TYPE_INSTALLABLE_FILE (FILE_TYPE_OPENGL_LIB | \ + FILE_TYPE_XLIB_LIB | \ + FILE_TYPE_TLS_LIB | \ + FILE_TYPE_UTILITY_LIB | \ + FILE_TYPE_DOCUMENTATION | \ + FILE_TYPE_OPENGL_HEADER | \ + FILE_TYPE_KERNEL_MODULE | \ + FILE_TYPE_INSTALLER_BINARY | \ + FILE_TYPE_UTILITY_BINARY | \ + FILE_TYPE_LIBGL_LA | \ + FILE_TYPE_XMODULE_LIB | \ + FILE_TYPE_DOT_DESKTOP) + +#define FILE_TYPE_HAVE_PATH (FILE_TYPE_OPENGL_LIB | \ + FILE_TYPE_OPENGL_SYMLINK | \ + FILE_TYPE_LIBGL_LA | \ + FILE_TYPE_XLIB_LIB | \ + FILE_TYPE_XLIB_SYMLINK | \ + FILE_TYPE_TLS_LIB | \ + FILE_TYPE_TLS_SYMLINK | \ + FILE_TYPE_UTILITY_LIB | \ + FILE_TYPE_UTILITY_SYMLINK | \ + FILE_TYPE_XMODULE_LIB | \ + FILE_TYPE_XMODULE_SYMLINK | \ FILE_TYPE_DOCUMENTATION) -#define FILE_TYPE_HAVE_ARCH (FILE_TYPE_OPENGL_LIB | \ - FILE_TYPE_OPENGL_SYMLINK | \ - FILE_TYPE_LIBGL_LA | \ - FILE_TYPE_TLS_LIB | \ +#define FILE_TYPE_HAVE_ARCH (FILE_TYPE_OPENGL_LIB | \ + FILE_TYPE_OPENGL_SYMLINK | \ + FILE_TYPE_LIBGL_LA | \ + FILE_TYPE_TLS_LIB | \ FILE_TYPE_TLS_SYMLINK) -#define FILE_TYPE_HAVE_CLASS (FILE_TYPE_TLS_LIB | \ +#define FILE_TYPE_HAVE_CLASS (FILE_TYPE_TLS_LIB | \ FILE_TYPE_TLS_SYMLINK) -#define FILE_TYPE_SYMLINK (FILE_TYPE_OPENGL_SYMLINK | \ - FILE_TYPE_XFREE86_SYMLINK | \ - FILE_TYPE_TLS_SYMLINK) +#define FILE_TYPE_SYMLINK (FILE_TYPE_OPENGL_SYMLINK | \ + FILE_TYPE_XLIB_SYMLINK | \ + FILE_TYPE_TLS_SYMLINK | \ + FILE_TYPE_XMODULE_SYMLINK | \ + FILE_TYPE_UTILITY_SYMLINK) -#define FILE_TYPE_RTLD_CHECKED (FILE_TYPE_OPENGL_LIB | \ +#define FILE_TYPE_RTLD_CHECKED (FILE_TYPE_OPENGL_LIB | \ FILE_TYPE_TLS_LIB) +#define FILE_TYPE_SHARED_LIB (FILE_TYPE_OPENGL_LIB | \ + FILE_TYPE_XLIB_SHARED_LIB | \ + FILE_TYPE_TLS_LIB | \ + FILE_TYPE_XMODULE_SHARED_LIB | \ + FILE_TYPE_UTILITY_LIB) #define TLS_LIB_TYPE_FORCED 0x0001 #define TLS_LIB_NEW_TLS 0x0002 #define TLS_LIB_CLASSIC_TLS 0x0004 +#define SELINUX_DEFAULT 0x0000 +#define SELINUX_FORCE_YES 0x0001 +#define SELINUX_FORCE_NO 0x0002 + #define FORCE_CLASSIC_TLS (TLS_LIB_CLASSIC_TLS | TLS_LIB_TYPE_FORCED) #define FORCE_NEW_TLS (TLS_LIB_NEW_TLS | TLS_LIB_TYPE_FORCED) @@ -328,6 +372,8 @@ typedef struct { #define OPENGL_HEADER_DST_PATH "include/GL" #define INSTALLER_BINARY_DST_PATH "bin" #define UTILITY_BINARY_DST_PATH "bin" +#define DOCUMENTATION_DST_PATH "share/doc/NVIDIA_GLX-1.0" +#define DOT_DESKTOP_DST_PATH "share/applications" #define LICENSE_FILE "LICENSE" diff --git a/option_table.h b/option_table.h new file mode 100644 index 0000000..e7cc9a7 --- /dev/null +++ b/option_table.h @@ -0,0 +1,352 @@ +#define NVOPT_HAS_ARGUMENT 0x1 +#define NVOPT_IS_BOOLEAN 0x2 + +#define OPTION_HELP_ALWAYS 0x8000 + +typedef struct { + const char *name; + int val; + unsigned int flags; + char *description; /* not used by nvgetopt() */ +} NVOption; + +enum { + XFREE86_PREFIX_OPTION = 1, + OPENGL_PREFIX_OPTION, + KERNEL_INCLUDE_PATH_OPTION, + KERNEL_INSTALL_PATH_OPTION, + UNINSTALL_OPTION, + PROC_MOUNT_POINT_OPTION, + USER_INTERFACE_OPTION, + LOG_FILE_NAME_OPTION, + HELP_ARGS_ONLY_OPTION, + TMPDIR_OPTION, + NO_OPENGL_HEADERS_OPTION, + INSTALLER_PREFIX_OPTION, + FORCE_TLS_OPTION, + SANITY_OPTION, + ADVANCED_OPTIONS_ARGS_ONLY_OPTION, + UTILITY_PREFIX_OPTION, + ADD_THIS_KERNEL_OPTION, + RPM_FILE_LIST_OPTION, + NO_RUNLEVEL_CHECK_OPTION, + PRECOMPILED_KERNEL_INTERFACES_PATH_OPTION, + NO_ABI_NOTE_OPTION, + KERNEL_SOURCE_PATH_OPTION, + NO_RPMS_OPTION, + X_PREFIX_OPTION, + KERNEL_OUTPUT_PATH_OPTION, + NO_RECURSION_OPTION, + FORCE_TLS_COMPAT32_OPTION, + COMPAT32_PREFIX_OPTION, + UPDATE_OPTION, + FORCE_SELINUX_OPTION, + NO_SIGWINCH_WORKAROUND_OPTION, + X_MODULE_PATH_OPTION, + NO_KERNEL_MODULE_OPTION +}; + +static const NVOption __options[] = { + /* These options are printed by "nvidia-installer --help" */ + + { "accept-license", 'a', OPTION_HELP_ALWAYS, + "Bypass the display and prompting for acceptance of the " + "NVIDIA Software License Agreement. By passing this option to " + "nvidia-installer, you indicate that you have read and accept the " + "License Agreement contained in the file 'LICENSE' (in the top " + "level directory of the driver package)." }, + + { "update", UPDATE_OPTION, OPTION_HELP_ALWAYS, + "Connect to the NVIDIA FTP server ' " DEFAULT_FTP_SITE " ' and determine the " + "latest available driver version. If there is a more recent " + "driver available, automatically download and install it. Any " + "other options given on the commandline will be passed on to the " + "downloaded driver package when installing it." }, + + { "version", 'v', OPTION_HELP_ALWAYS, + "Print the nvidia-installer version and exit." }, + + { "help", 'h', OPTION_HELP_ALWAYS, + "Print usage information for the common commandline options " + "and exit." }, + + { "advanced-options", 'A', OPTION_HELP_ALWAYS, + "Print usage information for the common commandline options " + "as well as the advanced options, and then exit." }, + + /* These options are only printed by "nvidia-installer --advanced-help" */ + + { "driver-info", 'i', 0, + "Print information about the currently installed NVIDIA " + "driver version." }, + + { "uninstall", UNINSTALL_OPTION, 0, + "Uninstall the currently installed NVIDIA driver." }, + + { "sanity", SANITY_OPTION, 0, + "Perform basic sanity tests on an existing NVIDIA " + "driver installation." }, + + { "expert", 'e', 0, + "Enable 'expert' installation mode; more detailed questions " + "will be asked, and more verbose output will be printed; " + "intended for expert users. The questions may be suppressed " + "with the '--no-questions' commandline option." }, + + { "no-questions", 'q', 0, + "Do not ask any questions; the default (normally 'yes') " + "is assumed for " + "all yes/no questions, and the default string is assumed in " + "any situation where the user is prompted for string input. " + "The one question that is not bypassed by this option is " + "license acceptance; the license may be accepted with the " + "commandline option '--accept-license'." }, + + { "silent", 's', 0, + "Run silently; no questions are asked and no output is " + "printed, except for error messages to stderr. This option " + "implies '--ui=none --no-questions --accept-license'." }, + + { "x-prefix", X_PREFIX_OPTION, NVOPT_HAS_ARGUMENT, + "The prefix under which the X components of the " + "NVIDIA driver will be installed; the default is: '" + DEFAULT_XFREE86_INSTALLATION_PREFIX + "'. Only under rare circumstances should this option be used." }, + + { "xfree86-prefix", XFREE86_PREFIX_OPTION, NVOPT_HAS_ARGUMENT, + "This is a deprecated synonym for --x-prefix." }, + + { "x-module-path", X_MODULE_PATH_OPTION, NVOPT_HAS_ARGUMENT, + "The path under which the NVIDIA X server modules will be installed. " + "If `pkg-config --variable=moduledir xorg-server` is successful and " + "returns a directory that exists, then that is the default; otherwise, " + "this value defaults to the X prefix (which defaults to '" + DEFAULT_XFREE86_INSTALLATION_PREFIX "', but can be overridden with the " + "'--x-prefix' option) plus \"lib/modules\"." }, + + { "opengl-prefix", OPENGL_PREFIX_OPTION, NVOPT_HAS_ARGUMENT, + "The prefix under which the OpenGL components of the " + "NVIDIA driver will be installed; the default is: '" + DEFAULT_OPENGL_INSTALLATION_PREFIX + "'. Only under rare circumstances should this option be used. " + "The Linux OpenGL ABI (http://oss.sgi.com/projects/ogl-sample/ABI/) " + "mandates this default value." }, + +#if defined(NV_X86_64) + { "compat32-prefix", COMPAT32_PREFIX_OPTION, NVOPT_HAS_ARGUMENT, + "The path relative to which the 32bit compatibility " + "libraries will be installed on x86-64 systems; this option " + "is unset by default, the OpenGL prefix alone determines " + "the target location. Only under very rare circumstances " + "should this option need to be used." }, +#endif /* NV_X86_64 */ + + { "installer-prefix", INSTALLER_PREFIX_OPTION, NVOPT_HAS_ARGUMENT, + "The prefix under which the installer binary will be " + "installed; the default is: '" DEFAULT_INSTALLER_INSTALLATION_PREFIX + "'. Note: use the \"--utility-prefix\" option instead." }, + + { "utility-prefix", UTILITY_PREFIX_OPTION, NVOPT_HAS_ARGUMENT, + "The prefix under which the various NVIDIA utilities " + "(nvidia-installer, nvidia-settings, nvidia-xconfig, " + "nvidia-bug-report.sh) will be installed; the default is: '" + DEFAULT_UTILITY_INSTALLATION_PREFIX "'." }, + + { "kernel-include-path", KERNEL_INCLUDE_PATH_OPTION, NVOPT_HAS_ARGUMENT, + "The directory containing the kernel include files that " + "should be used when compiling the NVIDIA kernel module. " + "This option is deprecated; please use '--kernel-source-path' " + "instead." }, + + { "kernel-source-path", KERNEL_SOURCE_PATH_OPTION, NVOPT_HAS_ARGUMENT, + "The directory containing the kernel source files that " + "should be used when compiling the NVIDIA kernel module. " + "When not specified, the installer will use " + "'/lib/modules/`uname -r`/build', if that " + "directory exists. Otherwise, it will use " + "'/usr/src/linux'." }, + + { "kernel-output-path", KERNEL_OUTPUT_PATH_OPTION, NVOPT_HAS_ARGUMENT, + "The directory containing any KBUILD output files if " + "either one of the 'KBUILD_OUTPUT' or 'O' parameters were " + "passed to KBUILD when building the kernel image/modules. " + "When not specified, the installer will assume that no " + "separate output directory was used." }, + + { "kernel-install-path", KERNEL_INSTALL_PATH_OPTION, NVOPT_HAS_ARGUMENT, + "The directory in which the NVIDIA kernel module should be " + "installed. The default value is either '/lib/modules/`uname " + "-r`/kernel/drivers/video' (if '/lib/modules/`uname -r`/kernel' " + "exists) or '/lib/modules/`uname -r`/video'." }, + + { "proc-mount-point", PROC_MOUNT_POINT_OPTION, NVOPT_HAS_ARGUMENT, + "The mount point for the proc file system; if not " + "specified, then this value defaults to '" DEFAULT_PROC_MOUNT_POINT + "' (which is normally " + "correct). The mount point of the proc filesystem is needed " + "because the contents of '/version' is used when " + "identifying if a precompiled kernel interface is available for " + "the currently running kernel. This option should only be needed " + "in very rare circumstances." }, + + { "log-file-name", LOG_FILE_NAME_OPTION, NVOPT_HAS_ARGUMENT, + "File name of the installation log file (the default is: " + "'" DEFAULT_LOG_FILE_NAME "')." }, + + { "tmpdir", TMPDIR_OPTION, NVOPT_HAS_ARGUMENT, + "Use the specified directory as a temporary directory when " + "downloading files from the NVIDIA ftp site; " + "if not given, then the following list will be searched, and " + "the first one that exists will be used: $TMPDIR, /tmp, ., " + "$HOME." }, + + { "ftp-mirror", 'm', NVOPT_HAS_ARGUMENT, + "Use the specified FTP mirror rather than the default ' " + DEFAULT_FTP_SITE + " ' when downloading driver updates." }, + + { "latest", 'l', 0, + "Connect to the NVIDIA FTP server ' " DEFAULT_FTP_SITE " ' " + "(or use the ftp mirror " + "specified with the '--ftp-mirror' option) and query the most " + "recent " INSTALLER_OS "-" INSTALLER_ARCH " driver version number." }, + + { "force-update", 'f', 0, + "Forces an update to proceed, even if the installer " + "thinks the latest driver is already installed; this option " + "implies '--update'." }, + + { "ui", USER_INTERFACE_OPTION, NVOPT_HAS_ARGUMENT, + "Specify what user interface to use, if available. " + "Valid values for [UI] are 'ncurses' (the default) or 'none'. " + "If the ncurses interface fails to initialize, or 'none' " + "is specified, then a simple printf/scanf interface will " + "be used." }, + + { "no-ncurses-color", 'c', 0, + "Disable use of color in the ncurses user interface." }, + + { "no-opengl-headers", NO_OPENGL_HEADERS_OPTION, 0, + "Normally, installation will install NVIDIA's OpenGL " + "header files. This option disables installation of the NVIDIA " + "OpenGL header files." }, + + { "force-tls", FORCE_TLS_OPTION, NVOPT_HAS_ARGUMENT, + "NVIDIA's OpenGL libraries are compiled with one of two " + "different thread local storage (TLS) mechanisms: 'classic tls' " + "which is used on systems with glibc 2.2 or older, and 'new tls' " + "which is used on systems with tls-enabled glibc 2.3 or newer. " + "The nvidia-installer will select the OpenGL " + "libraries appropriate for your system; however, you may use " + "this option to force the installer to install one library " + "type or another. Valid values for [FORCE-TLS] are 'new' and " + "'classic'." }, + +#if defined(NV_X86_64) + { "force-tls-compat32", FORCE_TLS_COMPAT32_OPTION, NVOPT_HAS_ARGUMENT, + "This option forces the installer to install a specific " + "32bit compatibility OpenGL TLS library; further details " + "can be found in the description of the '--force-tls' option." }, +#endif /* NV_X86_64 */ + + { "kernel-name", 'k', NVOPT_HAS_ARGUMENT, + "Build and install the NVIDIA kernel module for the " + "non-running kernel specified by [KERNEL-NAME] ([KERNEL-NAME] " + "should be the output of `uname -r` when the target kernel is " + "actually running). This option implies " + "'--no-precompiled-interface'. If the options " + "'--kernel-install-path' and '--kernel-source-path' are not " + "given, then they will be inferred from [KERNEL-NAME]; eg: " + "'/lib/modules/[KERNEL-NAME]/kernel/drivers/video/' and " + "'/lib/modules/[KERNEL-NAME]/build/', respectively." }, + + { "no-precompiled-interface", 'n', 0, + "Disable use of precompiled kernel interfaces." }, + + { "no-runlevel-check", NO_RUNLEVEL_CHECK_OPTION, 0, + "Normally, the installer checks the current runlevel and " + "warns users if they are in runlevel 1: in runlevel 1, some " + "services that are normally active are disabled (such as devfs), " + "making it difficult for the installer to properly setup the " + "kernel module configuration files. This option disables the " + "runlevel check." }, + + { "no-abi-note", NO_ABI_NOTE_OPTION, 0, + "The NVIDIA OpenGL libraries contain an OS ABI note tag, " + "which identifies the minimum kernel version needed to use the " + "library. This option causes the installer to remove this note " + "from the OpenGL libraries during installation." }, + + { "no-rpms", NO_RPMS_OPTION, 0, + "Normally, the installer will check for several rpms that " + "conflict with the driver (specifically: NVIDIA_GLX and " + "NVIDIA_kernel), and remove them if present. This option " + "disables this check." }, + + { "no-backup", 'b', 0, + "During driver installation, conflicting files are backed " + "up, so that they can be restored when the driver is " + "uninstalled. This option causes the installer to simply delete " + "conflicting files, rather than back them up." }, + + { "no-network", 'N', 0, + "This option instructs the installer to not attempt to " + "connect to the NVIDIA ftp site (for updated precompiled kernel " + "interfaces, for example)." }, + + { "no-recursion", NO_RECURSION_OPTION, 0, + "Normally, nvidia-installer will recursively search for " + "potentially conflicting libraries under the default OpenGL " + "and X server installation locations. With this option set, " + "the installer will only search in the top-level directories." }, + + { "kernel-module-only", 'K', 0, + "Install a kernel module only, and do not uninstall the " + "existing driver. This is intended to be used to install kernel " + "modules for additional kernels (in cases where you might boot " + "between several different kernels). To use this option, you " + "must already have a driver installed, and the version of the " + "installed driver must match the version of this kernel " + "module." }, + + { "no-kernel-module", NO_KERNEL_MODULE_OPTION, 0, + "Install everything but the kernel module, and do not remove any " + "existing, possibly conflicting kernel modules. This can be " + "useful in some DEBUG environments. If you use this option, you " + "must be careful to ensure that a NVIDIA kernel module matching " + "this driver version is installed seperately." }, + + { "precompiled-kernel-interfaces-path", + PRECOMPILED_KERNEL_INTERFACES_PATH_OPTION, NVOPT_HAS_ARGUMENT, + "Before searching for a precompiled kernel interface in the " + ".run file, search in the specified directory." }, + + { "force-selinux", FORCE_SELINUX_OPTION, NVOPT_HAS_ARGUMENT, + "Linux installations using SELinux (Security-Enhanced Linux) " + "require that the security type of all shared libraries be set " + "to 'shlib_t'. nvidia-installer will detect when to set " + "the security type, and set it using chcon(1) on the shared " + "libraries it installs. Use this option to override " + "nvidia-installer's detection of when to set the security type. " + "Valid values for [FORCE-SELINUX] are 'yes' (force setting of the " + "security type), " + "'no' (prevent setting of the security type), and 'default' " + "(let nvidia-installer decide when to set the security type)." }, + + { "no-sigwinch-workaround", NO_SIGWINCH_WORKAROUND_OPTION, 0, + "Normally, nvidia-installer ignores the SIGWINCH signal before it " + "forks to execute commands, e.g. to build the kernel module, and " + "restores the SIGWINCH signal handler after the child process " + "has terminated. This option disables this behavior." }, + + /* Orphaned options: These options were in the long_options table in + * nvidia-installer.c but not in the help. */ + { "debug", 'd', 0, NULL }, + { "help-args-only", HELP_ARGS_ONLY_OPTION, 0, NULL }, + { "add-this-kernel", ADD_THIS_KERNEL_OPTION, 0, NULL }, + { "rpm-file-list", RPM_FILE_LIST_OPTION, NVOPT_HAS_ARGUMENT, NULL }, + { "no-rpms", NO_RPMS_OPTION, 0, NULL}, + { "advanced-options-args-only", ADVANCED_OPTIONS_ARGS_ONLY_OPTION, 0, NULL }, + + { NULL, 0, 0, NULL }, +}; diff --git a/precompiled.c b/precompiled.c index 1a5ef46..ae91390 100644 --- a/precompiled.c +++ b/precompiled.c @@ -54,20 +54,20 @@ * bytes, and build a uint32. */ -static uint32 decode_uint32(uint8 *buf) +static uint32 decode_uint32(char *buf) { uint32 ret = 0; - ret += (uint32) buf[3]; + ret += (((uint32) buf[3]) & 0xff); ret <<= 8; - ret += (uint32) buf[2]; + ret += (((uint32) buf[2]) & 0xff); ret <<= 8; - ret += (uint32) buf[1]; + ret += (((uint32) buf[1]) & 0xff); ret <<= 8; - ret += (uint32) buf[0]; + ret += (((uint32) buf[0]) & 0xff); ret <<= 0; return ret; @@ -158,7 +158,7 @@ PrecompiledInfo *precompiled_unpack(Options *op, const int package_patch) { int dst_fd, fd, offset, len = 0; - uint8 *buf, *dst; + char *buf, *dst; uint32 crc, major, minor, patch, val, size; char *description, *proc_version_string; struct stat stat_buf; diff --git a/sanity.c b/sanity.c index abd1025..3af6796 100644 --- a/sanity.c +++ b/sanity.c @@ -135,187 +135,3 @@ int check_sysvipc(Options *op) return ret; } /* check_sysvipc() */ - - -#if 0 - - -/* - * XXX don't have time to finish implementing and testing this right - * now... - */ - - - - -/* - * find_conflicting_libraries() - - */ - -static int find_conflicting_libraries(Options *op) -{ - FileList *l; - struct stat stat_buf; - int i; - - l = (FileList *) nvalloc(sizeof(FileList)); - - /* search for possibly conflicting libraries */ - - find_conflicting_xfree86_libraries(op, DEFAULT_XFREE86_INSTALLATION_PREFIX, l); - - if (strcmp(DEFAULT_XFREE86_INSTALLATION_PREFIX, op->xfree86_prefix) != 0) - find_conflicting_xfree86_libraries(op, op->xfree86_prefix, l); - - find_conflicting_opengl_libraries(op, DEFAULT_OPENGL_INSTALLATION_PREFIX, l); - - if (strcmp(DEFAULT_OPENGL_INSTALLATION_PREFIX, op->opengl_prefix) != 0) - find_conflicting_opengl_libraries(op, op->opengl_prefix, l); - -#if defined(NV_X86_64) - if (op->compat32_prefix != NULL) { - char *prefix = nvstrcat(op->compat32_prefix, - DEFAULT_OPENGL_INSTALLATION_PREFIX, NULL); - find_conflicting_opengl_libraries(op, prefix, l); - nvfree(prefix); - - if (strcmp(DEFAULT_OPENGL_INSTALLATION_PREFIX, - op->opengl_prefix) != 0) { - prefix = nvstrcat(op->compat32_prefix, op->opengl_prefix, NULL); - find_conflicting_opengl_libraries(op, prefix, l); - nvfree(prefix); - } - } -#endif /* NV_X86_64 */ - - /* condense the file list */ - - condense_file_list(l); - - /* for each file in the list, check if it's an NVIDIA file */ - - for (i = 0; i < l->num; i++) { - if (lstat(l->filename[i], &stat_buf) == -1) { - ui_error(op, "Unable to determine properties for file '%s' (%s).", - l->filename[i], strerror(errno)); - continue; - } - - if (S_ISREG(stat_buf.st_mode)) { - ret = is_nvidia_library(op, l->filename[i]); - } else if (S_ISLNK(stat_buf.st_mode)) { - ret = is_nvidia_symlink(op, l->filename[i]); - } - } - - - - - /* free the FileList */ - - for (i = 0; i < l->num; i++) free(l->filename[i]); - free(l->filename); - free(l); - -} /* find_conflicting_libraries() */ - - - -/* - * is_nvidia_library() - mmap the file and scan through it for the - * nvidia string. - */ - -static int is_nvidia_library(Options *op, const char *filename) -{ - int fd = -1, ret = FALSE; - struct stat stat_buf; - char *buf = (void *) -1, char *found; - - if ((fd = open(filename, O_RDONLY)) == -1) { - ui_error(op, "Unable to open '%s' for reading (%s)", - filename, strerror(errno)); - goto done: - } - - if (fstat(fd, &stat_buf) == -1) { - ui_error(op, "Unable to determine size of '%s' (%s)", - filename, strerror(errno)); - goto done; - } - - if ((buf = mmap(0, stat_buf.st_size, PROT_READ, - MAP_FILE | MAP_SHARED, fd, 0)) == (void *) -1) { - ui_error(op, "Unable to map file '%s' for reading (%s)", - filename, strerror(errno)); - goto done; - } - - found = strstr(buf, "nvidia id: "); - - if (found) ret = TRUE; - - done: - - if (buf != (void *) -1) munmap(buf, stat_buf.st_size); - if (fd != -1) close(fd); - - return ret; - -} /* is_nvidia_library() */ - - -/* - * is_nvidia_symlink() - returns TRUE if this symlink should be moved - * out of the way. Find the target of the symlink, and recursively - * call is_nvidia_symlink() if the target is a symlink, or call - * is_nvidia_library() if the target is a regular file. - * - * XXX do we need to do anything about cyclic links? - */ - -static int is_nvidia_symlink(Options *op, const char *filename) -{ - char *tmp, *tmp2, *dir, *target; - int ret = TRUE; - struct stat stat_buf; - - tmp = get_symlink_target(op, filename); - if (!tmp) return FALSE; - - /* - * prepend the basename of the file, unless the target is an - * abosolute path - */ - - if (tmp[0] != '/') { - tmp2 = nvstrdup(tmp); - dir = dirname(tmp2); - target = nvstrcat(dir, "/", tmp, NULL); - nvfree(tmp); - nvfree(tmp2); - } else { - target = tmp; - } - - - if (lstat(target, &stat_buf) == -1) { - ui_error(op, "Unable to determine properties for file '%s' (%s).", - target, strerror(errno)); - return TRUE; /* return TRUE so that we don't try to back it up */ - } - - if (S_ISREG(stat_buf.st_mode)) { - ret = is_nvidia_library(op, target); - } else if (S_ISLNK(stat_buf.st_mode)) { - ret = is_nvidia_symlink(op, target); - } - - nvfree(target); - - return ret; - -} /* is_nvidia_symlink() */ - - -#endif diff --git a/snarf-ftp.c b/snarf-ftp.c index 23e35db..1a26aa1 100644 --- a/snarf-ftp.c +++ b/snarf-ftp.c @@ -107,7 +107,7 @@ static char *get_line(UrlResource *rsrc, int control) char *end; char buf[SNARF_BUFSIZE+1]; - while ((bytes_read = read(control, buf, SNARF_BUFSIZE))) { + while ((bytes_read = read(control, buf, SNARF_BUFSIZE)) > 0) { if (buf[0] == '4' || buf[0] == '5') return NULL; @@ -118,7 +118,7 @@ static char *get_line(UrlResource *rsrc, int control) if (buf[bytes_read - 2] == '\r') buf[bytes_read - 2] = '\0'; - ui_expert(rsrc->op, buf); + ui_expert(rsrc->op, "%s", buf); if (isdigit(buf[0]) && buf[3] == ' ') { return strdup(buf); @@ -297,7 +297,7 @@ int ftp_transfer(UrlResource *rsrc) rsrc->proxy = get_proxy("FTP_PROXY"); - if (rsrc->proxy) { + if (rsrc->proxy && (rsrc->proxy[0] != '\0')) { return http_transfer(rsrc); } diff --git a/snarf-http.c b/snarf-http.c index 555c86e..7a089f0 100644 --- a/snarf-http.c +++ b/snarf-http.c @@ -224,6 +224,9 @@ static void free_http_header(HttpHeader *h) free(l); l = l1; } + + free(h); + } /* free_http_header() */ @@ -287,6 +290,7 @@ static char *get_request(UrlResource *rsrc) { char *request = NULL; char *auth = NULL; + char *tmp_auth = NULL; Url *u; u = rsrc->url; @@ -295,34 +299,38 @@ static char *get_request(UrlResource *rsrc) "Host: ", u->host, "\r\n", NULL); if (u->username && u->password) { - auth = nvstrcat(u->username, ":", u->password, NULL); - auth = base64(auth, strlen(auth)); - request = nvstrcat(request, "Authorization: Basic ", - auth, "\r\n", NULL); + tmp_auth = nvstrcat(u->username, ":", u->password, NULL); + auth = base64(tmp_auth, strlen(tmp_auth)); + nvfree(tmp_auth); + NV_STRCAT(request, "Authorization: Basic ", + auth, "\r\n", NULL); + nvfree(auth); } if (rsrc->proxy_username && rsrc->proxy_password) { - auth = nvstrcat(rsrc->proxy_username, ":", - rsrc->proxy_password, NULL); - auth = base64(auth, strlen(auth)); - request = nvstrcat(request, "Proxy-Authorization: Basic ", - auth, "\r\n", NULL); + tmp_auth = nvstrcat(rsrc->proxy_username, ":", + rsrc->proxy_password, NULL); + auth = base64(tmp_auth, strlen(tmp_auth)); + nvfree(tmp_auth); + NV_STRCAT(request, "Proxy-Authorization: Basic ", + auth, "\r\n", NULL); + nvfree(auth); } - request = nvstrcat(request, "User-Agent: ", PROGRAM_NAME, "/", - NVIDIA_INSTALLER_VERSION, NULL); + NV_STRCAT(request, "User-Agent: ", PROGRAM_NAME, "/", + NVIDIA_INSTALLER_VERSION, NULL); /* This CRLF pair closes the User-Agent key-value set. */ - request = nvstrcat(request, "\r\n", NULL); + NV_STRCAT(request, "\r\n", NULL); /* If SNARF_HTTP_REFERER is set, spoof it. */ if (getenv("SNARF_HTTP_REFERER")) { - request = nvstrcat(request, "Referer: ", - getenv("SNARF_HTTP_REFERER"), - "\r\n", NULL); + NV_STRCAT(request, "Referer: ", + getenv("SNARF_HTTP_REFERER"), + "\r\n", NULL); } - request = nvstrcat(request, "\r\n", NULL); + NV_STRCAT(request, "\r\n", NULL); return request; @@ -336,6 +344,7 @@ int http_transfer(UrlResource *rsrc) Url *redir_u = NULL; char *request = NULL; char *raw_header = NULL; + char *tmp_header = NULL; HttpHeader *header = NULL; char *len_string = NULL; char *new_location = NULL; @@ -422,7 +431,7 @@ int http_transfer(UrlResource *rsrc) bytes_read = read(sock, buf, 8); - if (bytes_read == 0) { + if (bytes_read <= 0) { close(sock); return FALSE; } @@ -433,13 +442,14 @@ int http_transfer(UrlResource *rsrc) } else { /* skip the header */ buf[bytes_read] = '\0'; - raw_header = get_raw_header(sock); - raw_header = nvstrcat(buf, raw_header, NULL); + tmp_header = get_raw_header(sock); + raw_header = nvstrcat(buf, tmp_header, NULL); + free(tmp_header); header = make_http_header(raw_header); /* if in expert mode, write the raw_header to the log */ - ui_expert(rsrc->op, raw_header); + ui_expert(rsrc->op, "%s", raw_header); /* check for redirects */ new_location = get_header_value("location", header); diff --git a/snarf.c b/snarf.c index 2788e4f..147fcb5 100644 --- a/snarf.c +++ b/snarf.c @@ -231,7 +231,7 @@ int dump_data(UrlResource *rsrc, int sock) ui_status_begin(rsrc->op, msg, "Downloading"); } - while ((bytes_read = read(sock, buf, SNARF_BUFSIZE))) { + while ((bytes_read = read(sock, buf, SNARF_BUFSIZE)) > 0) { if (rsrc->flags & SNARF_FLAGS_STATUS_BAR) { total_bytes_read += bytes_read; diff --git a/update.c b/update.c index fd3e8aa..3a7985d 100644 --- a/update.c +++ b/update.c @@ -195,13 +195,6 @@ char *append_update_arguments(char *s, int c, const char *arg, if (!s) s = nvstrcat(" ", NULL); - /* - * don't place "--update" or "--force-update" in the update - * argument list (avoid infinite loop) - */ - - if ((c == 'u') || (c == 'f')) return s; - do { if (l[i].val == c) { t = nvstrcat(s, " --", l[i].name, NULL); @@ -230,6 +223,7 @@ static char *get_latest_driver_version_and_filename(Options *op, int *major, int *minor, int *patch) { int fd = -1; + int length; char *tmpfile = NULL; char *url = NULL; char *str = (void *) -1; @@ -259,8 +253,10 @@ static char *get_latest_driver_version_and_filename(Options *op, int *major, strerror(errno)); goto done; } + + length = stat_buf.st_size; - str = mmap(0, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0); + str = mmap(0, length, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0); if (str == (void *) -1) { ui_error(op, "Unable to determine most recent NVIDIA %s-%s driver " "version (%s).", INSTALLER_OS, INSTALLER_ARCH, @@ -268,7 +264,7 @@ static char *get_latest_driver_version_and_filename(Options *op, int *major, goto done; } - buf = get_next_line(str, NULL); + buf = get_next_line(str, NULL, str, length); if (!nvid_version(buf, major, minor, patch)) { ui_error(op, "Unable to determine latest NVIDIA %s-%s driver " diff --git a/user-interface.c b/user-interface.c index 1ec24ea..55b7b2c 100644 --- a/user-interface.c +++ b/user-interface.c @@ -62,7 +62,7 @@ extern InstallerUI stream_ui_dispatch_table; /* pull in the user interface data arrays and sizes */ -extern const unsigned char ncurses_ui_array[]; +extern const char ncurses_ui_array[]; extern const int ncurses_ui_array_size; /* struct describing the ui data */ @@ -324,7 +324,7 @@ void ui_command_output(Options *op, const char *fmt, ...) if (!op->silent) __ui->command_output(op, msg); - log_printf(op, FALSE, NV_CMD_OUT_PREFIX, msg); + log_printf(op, FALSE, NV_CMD_OUT_PREFIX, "%s", msg); free(msg); -- cgit v1.2.3