diff options
-rw-r--r-- | DRIVER_VERSION | 2 | ||||
-rw-r--r-- | backup.c | 181 | ||||
-rw-r--r-- | backup.h | 3 | ||||
-rw-r--r-- | command-list.c | 35 | ||||
-rw-r--r-- | command-list.h | 2 | ||||
-rw-r--r-- | files.c | 284 | ||||
-rw-r--r-- | install-from-cwd.c | 80 | ||||
-rw-r--r-- | kernel.c | 52 | ||||
-rw-r--r-- | kernel.h | 1 | ||||
-rw-r--r-- | misc.c | 218 | ||||
-rw-r--r-- | misc.h | 2 | ||||
-rw-r--r-- | mkprecompiled.c | 87 | ||||
-rw-r--r-- | nvidia-installer.h | 20 | ||||
-rw-r--r-- | precompiled.c | 37 | ||||
-rw-r--r-- | precompiled.h | 8 | ||||
-rw-r--r-- | sanity.c | 19 | ||||
-rw-r--r-- | update.c | 167 |
17 files changed, 790 insertions, 408 deletions
diff --git a/DRIVER_VERSION b/DRIVER_VERSION index 4ae16bf..aa30fc2 100644 --- a/DRIVER_VERSION +++ b/DRIVER_VERSION @@ -1 +1 @@ -1.0-7185 +71.86.01 @@ -126,7 +126,7 @@ static int do_uninstall(Options *op); static int sanity_check_backup_log_entries(Options *op, BackupInfo *b); - +static char *create_backwards_compatible_version_string(const char *str); @@ -141,6 +141,7 @@ static int sanity_check_backup_log_entries(Options *op, BackupInfo *b); int init_backup(Options *op, Package *p) { + char *version; FILE *log; /* remove the directory, if it already exists */ @@ -168,9 +169,13 @@ int init_backup(Options *op, Package *p) /* write the version and description */ - fprintf(log, "%s\n", p->version_string); - fprintf(log, "%s\n", p->description); + version = create_backwards_compatible_version_string(p->version); + fprintf(log, "%s\n", version); + fprintf(log, "%s\n", p->description); + + nvfree(version); + /* close the log file */ if (fclose(log) != 0) { @@ -494,9 +499,9 @@ static int do_uninstall(Options *op) "Your driver installation has been " "altered since it was initially installed; this may happen, " "for example, if you have since installed the NVIDIA driver through " - "a mechanism other than the nvidia-installer (such as rpm or " - "with the NVIDIA tarballs). The nvidia-installer will " - "attempt to uninstall as best it can."; + "a mechanism other than nvidia-installer (such as your " + "distribution's native package management system). " + "nvidia-installer will attempt to uninstall as best it can."; /* do we even have a backup directory? */ @@ -982,12 +987,14 @@ static int check_backup_log_entries(Options *op, BackupInfo *b) * XXX we should probably check the file permissions of BACKUP_LOG. */ -char *get_installed_driver_version_and_descr(Options *op, int *major, - int *minor, int *patch) +int get_installed_driver_version_and_descr(Options *op, + char **pVersion, char **pDescr) { struct stat stat_buf; char *c, *version = NULL, *descr = NULL, *buf = NULL; + char *version_line = NULL; int length, fd = -1; + int ret = FALSE; if ((fd = open(BACKUP_LOG, O_RDONLY)) == -1) goto done; @@ -1000,18 +1007,31 @@ char *get_installed_driver_version_and_descr(Options *op, int *major, buf = mmap(0, length, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0); if (!buf) goto done; - version = get_next_line(buf, &c, buf, length); - if (!version) goto done; + version_line = get_next_line(buf, &c, buf, length); + if (!version_line) goto done; - if (!nvid_version(version, major, minor, patch)) goto done; + version = extract_version_string(version_line); + + if (!version) goto done; descr = get_next_line(c, NULL, buf, length); + if (!descr) goto done; + + *pVersion = strdup(version); + *pDescr = strdup(descr); + + ret = TRUE; + done: - if (version) free(version); + nvfree(version_line); + nvfree(version); + nvfree(descr); + if (buf) munmap(buf, stat_buf.st_size); if (fd != -1) close(fd); - return descr; + + return ret; } /* get_installed_driver_version_and_descr() */ @@ -1033,30 +1053,30 @@ char *get_installed_driver_version_and_descr(Options *op, int *major, int check_for_existing_driver(Options *op, Package *p) { - int major, minor, patch; - char *descr; + char *descr = NULL; + char *version = NULL; + int ret = FALSE; + int localRet; if (!check_for_existing_rpms(op)) return FALSE; - descr = get_installed_driver_version_and_descr(op, &major, &minor, &patch); + localRet = get_installed_driver_version_and_descr(op, &version, &descr); if (op->kernel_module_only) { - if (!descr) { + if (!localRet) { ui_error(op, "No NVIDIA driver is currently installed; the " "'--kernel-module-only' option can only be used " "to install the NVIDIA kernel module on top of an " "existing driver installation."); return FALSE; } else { - if ((p->major != major) || - (p->minor != minor) || - (p->patch != patch)) { + if (strcmp(p->version, version) != 0) { ui_error(op, "The '--kernel-module-only' option can only be " "used to install a kernel module on top of an " "existing driver installation of the same driver " "version. The existing driver installation is " - "%d.%d-%d, but the kernel module is %d.%d-%d\n", - major, minor, patch, p->major, p->minor, p->patch); + "%s, but the kernel module is %s.\n", + version, p->version); return FALSE; } else { return TRUE; @@ -1064,7 +1084,12 @@ int check_for_existing_driver(Options *op, Package *p) } } - if (!descr) return TRUE; + /* no existing driver -- it is fine to continue with installation */ + + if (!localRet) { + ret = TRUE; + goto done; + } /* * XXX we could do a comparison, here, to check that the Package @@ -1075,19 +1100,25 @@ int check_for_existing_driver(Options *op, Package *p) */ if (!ui_yes_no(op, TRUE, "There appears to already be a driver installed " - "on your system (version: %d.%d-%d). As part of " - "installing this driver (version: %d.%d-%d), the existing " + "on your system (version: %s). As part of " + "installing this driver (version: %s), the existing " "driver will be uninstalled. Are you sure you want to " "continue? ('no' will abort installation)", - major, minor, patch, p->major, p->minor, p->patch)) { + version, p->version)) { free(descr); ui_log(op, "Installation aborted."); return FALSE; } - free(descr); - return TRUE; + ret = TRUE; + + done: + + nvfree(descr); + nvfree(version); + + return ret; } /* check_for_existing_driver() */ @@ -1103,11 +1134,12 @@ int check_for_existing_driver(Options *op, Package *p) int uninstall_existing_driver(Options *op, const int interactive) { - int major, minor, patch, ret; - char *descr; + int ret; + char *descr = NULL; + char *version = NULL; - descr = get_installed_driver_version_and_descr(op, &major, &minor, &patch); - if (!descr) { + ret = get_installed_driver_version_and_descr(op, &version, &descr); + if (!ret) { if (interactive) { ui_message(op, "There is no NVIDIA driver currently installed."); } @@ -1118,17 +1150,18 @@ int uninstall_existing_driver(Options *op, const int interactive) if (ret) { if (interactive) { - ui_message(op, "Uninstallation of existing driver: %s (%d.%d-%d) " - "is complete.", descr, major, minor, patch); + ui_message(op, "Uninstallation of existing driver: %s (%s) " + "is complete.", descr, version); } else { - ui_log(op, "Uninstallation of existing driver: %s (%d.%d-%d) " - "is complete.", descr, major, minor, patch); + ui_log(op, "Uninstallation of existing driver: %s (%s) " + "is complete.", descr, version); } } else { ui_error(op, "Uninstallation failed."); } - free(descr); + nvfree(descr); + nvfree(version); return TRUE; @@ -1143,19 +1176,21 @@ int uninstall_existing_driver(Options *op, const int interactive) int report_driver_information(Options *op) { - int major, minor, patch; - char *descr; - - descr = get_installed_driver_version_and_descr(op, &major, &minor, &patch); - if (!descr) { + char *descr, *version; + int ret; + + ret = get_installed_driver_version_and_descr(op, &version, &descr); + if (!ret) { ui_message(op, "There is no NVIDIA driver currently installed."); return FALSE; } ui_message(op, "The currently installed driver is: '%s' " - "(version: %d.%d-%d).", descr, major, minor, patch); + "(version: %s).", descr, version); - free(descr); + nvfree(descr); + nvfree(version); + return TRUE; } /* report_driver_information() */ @@ -1330,3 +1365,61 @@ static int sanity_check_backup_log_entries(Options *op, BackupInfo *b) return ret; } /* sanity_check_backup_log_entries */ + + + +/* + * create_backwards_compatible_version_string() - given the version + * string 'str', generate a version string to write to the backup log + * file that can be read by older nvidia-installers that assumed the + * X.Y-ZZZZ version format. + * + * Fortunately, old nvidia-installers' version parsing didn't care if + * there were extra digits beyond the four Z's (e.g., it could be + * X.Y-ZZZZZ, or X.Y-ZZZZZZZZ); they would just look for the first 4 + * Z's if they needed to parse the version. + * + * So, the strategy is to take the new version string, remove any + * periods, and print that out as the old style version, followed by + * the real version string in parenthesis; e.g., + * + * "1.0-105917 (105.9.17)" + * + * In this way, an old nvidia-installer will atleast be able to parse + * the string, even though it may not understand it, but a new + * nvidia-installer can be smart and pull out the new version string. + */ + +static char *create_backwards_compatible_version_string(const char *str) +{ + char *version, *scratch, *s, *t; + int len; + + /* + * create a scratch string by duping the passed in str, but + * collapse the scratch string by only retaining the digits; e.g., + * "105.9.17" --> "105917" + */ + + scratch = nvstrdup(str); + + for (s = t = scratch; *t; t++) { + if (isdigit(*t)) { + *s++ = *t; + } + } + + *s = '\0'; + + /* allocate a new string to contain the result */ + + len = strlen(str); + version = nvalloc((len * 2) + 16); + + sprintf(version, "1.0-%s (%s)", scratch, str); + + nvfree(scratch); + + return version; + +} /* create_backwards_compatible_version_string() */ @@ -36,12 +36,11 @@ int init_backup (Options*, Package*); int do_backup (Options*, const char*); int log_install_file (Options*, const char*); int log_create_symlink (Options*, const char*, const char*); -int get_installed_driver_version(Options*, int*, int*, int*); int check_for_existing_driver (Options*, Package*); int uninstall_existing_driver (Options*, const int); int report_driver_information (Options*); -char *get_installed_driver_version_and_descr(Options *, int *, int *, int *); +int get_installed_driver_version_and_descr(Options *, char **, char **); int test_installed_files(Options *op); int find_installed_file(Options *op, char *filename); diff --git a/command-list.c b/command-list.c index b35975e..583b2c7 100644 --- a/command-list.c +++ b/command-list.c @@ -65,6 +65,8 @@ static void find_conflicting_kernel_modules(Options *op, static void find_existing_files(Package *p, FileList *l, unsigned int); +static void condense_file_list(Package *p, FileList *l); + static void add_command (CommandList *c, int cmd, ...); static void add_file_to_list(const char*, const char*, FileList*); @@ -180,7 +182,7 @@ CommandList *build_command_list(Options *op, Package *p) /* condense the file list */ - condense_file_list(l); + condense_file_list(p, l); /* check the conflicting file list for any installed files */ @@ -715,10 +717,10 @@ static void find_conflicting_libraries(Options *op, * brute-force algorithm. */ -void condense_file_list(FileList *l) +static void condense_file_list(Package *p, FileList *l) { char **s = NULL; - int n = 0, i, j, match; + int n = 0, i, j, keep; struct stat stat_buf, *stat_bufs; @@ -740,12 +742,27 @@ void condense_file_list(FileList *l) */ for (i = 0; i < l->num; i++) { - match = FALSE; + keep = TRUE; if (lstat(l->filename[i], &stat_buf) == -1) continue; - - for (j = 0; j < n; j++) { + + /* + * check if this file is in the package we're trying to + * install; we don't want to remove files that are in the + * package; symlinks may have tricked us into looking for + * conflicting files inside our unpacked .run file. + */ + + for (j = 0; j < p->num_entries; j++) { + if ((p->entries[j].device == stat_buf.st_dev) && + (p->entries[j].inode == stat_buf.st_ino)) { + keep = FALSE; + break; + } + } + + for (j = 0; keep && (j < n); j++) { /* * determine if the two files are the same by comparing @@ -754,12 +771,12 @@ void condense_file_list(FileList *l) if ((stat_buf.st_dev == stat_bufs[j].st_dev) && (stat_buf.st_ino == stat_bufs[j].st_ino)) { - match = TRUE; + keep = FALSE; break; } } - - if (!match) { + + if (keep) { s = (char **) nvrealloc(s, sizeof(char *) * (n + 1)); s[n] = nvstrdup(l->filename[i]); stat_bufs[n] = stat_buf; diff --git a/command-list.h b/command-list.h index 6b2d225..5e70a1e 100644 --- a/command-list.h +++ b/command-list.h @@ -83,6 +83,4 @@ CommandList *build_command_list(Options*, Package *); void free_command_list(Options*, CommandList*); int execute_command_list(Options*, CommandList*, const char*, const char*); -void condense_file_list(FileList *l); - #endif /* __NVIDIA_INSTALLER_COMMAND_LIST_H__ */ @@ -866,35 +866,26 @@ int get_prefixes (Options *op) int add_kernel_module_to_package(Options *op, Package *p) { - int n, len; + char *file, *name, *dst; - n = p->num_entries; - - p->entries = - (PackageEntry *) nvrealloc(p->entries, (n + 1) * sizeof(PackageEntry)); + file = nvstrcat(p->kernel_module_build_directory, "/", + p->kernel_module_filename, NULL); - len = strlen(p->kernel_module_build_directory) + - strlen(p->kernel_module_filename) + 2; - p->entries[n].file = (char *) nvalloc(len); - snprintf(p->entries[n].file, len, "%s/%s", - p->kernel_module_build_directory, p->kernel_module_filename); - - p->entries[n].path = NULL; - p->entries[n].target = NULL; - p->entries[n].flags = FILE_TYPE_KERNEL_MODULE; - p->entries[n].mode = 0644; - - p->entries[n].name = strrchr(p->entries[n].file, '/'); - if (p->entries[n].name) p->entries[n].name++; - if (!p->entries[n].name) p->entries[n].name = p->entries[n].file; - - len = strlen(op->kernel_module_installation_path) + - strlen(p->kernel_module_filename) + 2; - p->entries[n].dst = (char *) nvalloc(len); - snprintf (p->entries[n].dst, len, "%s/%s", - op->kernel_module_installation_path, p->kernel_module_filename); - - p->num_entries++; + name = strrchr(file, '/'); + if (name) name++; + if (!name) name = file; + + dst = nvstrcat(op->kernel_module_installation_path, "/", + p->kernel_module_filename, NULL); + + add_package_entry(p, + file, + NULL, /* path */ + name, + NULL, /* target */ + dst, + FILE_TYPE_KERNEL_MODULE, + 0644); return TRUE; @@ -1402,7 +1393,6 @@ int copy_directory_contents(Options *op, const char *src, const char *dst) int pack_precompiled_kernel_interface(Options *op, Package *p) { char *cmd, time_str[256], *proc_version_string; - char major[16], minor[16], patch[16]; char *result, *descr; time_t t; struct utsname buf; @@ -1423,12 +1413,6 @@ int pack_precompiled_kernel_interface(Options *op, Package *p) proc_version_string = read_proc_version(op); - /* get the version strings */ - - snprintf(major, 16, "%d", p->major); - snprintf(minor, 16, "%d", p->minor); - snprintf(patch, 16, "%d", p->patch); - /* use the uname string as the description */ uname(&buf); @@ -1444,12 +1428,10 @@ int pack_precompiled_kernel_interface(Options *op, Package *p) PRECOMPILED_KERNEL_INTERFACE_FILENAME, " --output=", p->precompiled_kernel_interface_directory, "/", PRECOMPILED_KERNEL_INTERFACE_FILENAME, - "-", p->version_string, ".", time_str, + "-", p->version, ".", time_str, " --description=\"", descr, "\"", " --proc-version=\"", proc_version_string, "\"", - " --major=", major, - " --minor=", minor, - " --patch=", patch, NULL); + " --version=", p->version, NULL); /* execute the command */ @@ -1712,7 +1694,7 @@ done: void process_libGL_la_files(Options *op, Package *p) { - int i, n; + int i; char *tmpfile; char *tokens[3] = { "__LIBGL_PATH__", "__GENERATED_BY__", NULL }; @@ -1744,22 +1726,25 @@ void process_libGL_la_files(Options *op, Package *p) 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++; + + /* + * XXX 'name' is the basename (non-directory part) of + * the file to be installed; normally, 'name' just + * points into 'file', but in this case 'file' is + * mkstemp(3)-generated, so doesn't have the same + * basename; instead, we just strdup the name from the + * template package entry; yes, 'name' will get leaked + */ + + add_package_entry(p, + tmpfile, + p->entries[i].path, + nvstrdup(p->entries[i].name), + NULL, /* target */ + NULL, /* dst */ + ((p->entries[i].flags & FILE_CLASS_MASK) | + FILE_TYPE_LIBGL_LA), + p->entries[i].mode); } nvfree(replacements[0]); @@ -1781,7 +1766,7 @@ void process_libGL_la_files(Options *op, Package *p) void process_dot_desktop_files(Options *op, Package *p) { - int i, n; + int i; char *tmpfile; char *tokens[3] = { "__UTILS_PATH__", "__PIXMAP_PATH__", NULL }; @@ -1817,22 +1802,25 @@ void process_dot_desktop_files(Options *op, Package *p) 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++; + + /* + * XXX 'name' is the basename (non-directory part) of + * the file to be installed; normally, 'name' just + * points into 'file', but in this case 'file' is + * mkstemp(3)-generated, so doesn't have the same + * basename; instead, we just strdup the name from the + * template package entry; yes, 'name' will get leaked + */ + + add_package_entry(p, + tmpfile, + p->entries[i].path, + nvstrdup(p->entries[i].name), + NULL, /* target */ + NULL, /* dst */ + ((p->entries[i].flags & FILE_CLASS_MASK) | + FILE_TYPE_DOT_DESKTOP), + p->entries[i].mode); } } } @@ -1970,6 +1958,66 @@ static char *get_xdg_data_dir(void) } + +/* + * extract_x_path() - take a comma-separated list of directories, and + * extract the next available directory in the list. Assign the + * 'next' pointer so that it points to where we should continue during + * the next call of extract_x_path(). + * + * On success, return a pointer to the next directory in the string, + * and update the 'next' pointer. When we have exhausted the list, + * NULL is returned. + * + * Note that this will destructively replace commas with NULL + * terminators in the string. + */ + +static char *extract_x_path(char *str, char **next) +{ + char *start; + + /* + * choose where to start in the string: either we start at the + * beginning, or we start immediately after where we found a comma + * last time + */ + + start = str; + + if (*next) start = *next; + + /* skip past any commas at the start */ + + while (*start == ',') start++; + + /* if we hit the end of the string, return now */ + + if (*start == '\0') return NULL; + + /* + * find the next comma in the string; if we find one, change it to + * a NULL terminator (and move 'next' to the character immediately + * after the comma); if we don't find a comma, move the 'next' + * pointer to the end of the string, so that we terminate on the + * next call to extract_x_path() + */ + + *next = strchr(start, ','); + + if (*next) { + **next = '\0'; + (*next)++; + } else { + *next = strchr(start, '\0'); + } + + return start; + +} /* extract_x_path() */ + + + /* * get_x_paths_helper() - helper function for determining the X * library and module paths; returns 'TRUE' if we had to guess at the @@ -1983,7 +2031,7 @@ static int get_x_paths_helper(Options *op, char *name, char **path) { - char *dir, *cmd; + char *dirs, *cmd, *dir, *next; int ret, guessed = 0; /* @@ -2012,31 +2060,43 @@ static int get_x_paths_helper(Options *op, */ if (op->utils[XSERVER]) { - dir = NULL; + dirs = NULL; cmd = nvstrcat(op->utils[XSERVER], " ", xserver_cmd, NULL); - ret = run_command(op, cmd, &dir, FALSE, 0, TRUE); + ret = run_command(op, cmd, &dirs, FALSE, 0, TRUE); nvfree(cmd); - if ((ret == 0) && dir) { - - if (directory_exists(op, dir)) { - - ui_expert(op, "X %s path '%s' determined from `%s %s`", - name, dir, op->utils[XSERVER], xserver_cmd); + if ((ret == 0) && dirs) { + + next = NULL; - *path = dir; - return FALSE; + dir = extract_x_path(dirs, &next); + + while (dir) { + + if (directory_exists(op, dir)) { + + ui_expert(op, "X %s path '%s' determined from `%s %s`", + name, dir, op->utils[XSERVER], xserver_cmd); + + *path = nvstrdup(dir); + + nvfree(dirs); + + return FALSE; + + } else { + ui_warn(op, "You appear to be using a modular X.Org " + "release, but the X %s installation " + "path, '%s', reported by `%s %s` does not exist. " + "Please check your X.Org installation.", + name, dir, op->utils[XSERVER], xserver_cmd); + } - } else { - ui_warn(op, "You appear to be using a modular X.Org " - "release, but the X %s installation " - "path reported by `%s %s` does not exist. " - "Please check your X.Org installation.", - name, op->utils[XSERVER], xserver_cmd); + dir = extract_x_path(dirs, &next); } } - nvfree(dir); + nvfree(dirs); } /* @@ -2046,33 +2106,45 @@ static int get_x_paths_helper(Options *op, */ if (op->utils[PKG_CONFIG]) { - dir = NULL; + dirs = NULL; cmd = nvstrcat(op->utils[PKG_CONFIG], " ", pkg_config_cmd, NULL); - ret = run_command(op, cmd, &dir, FALSE, 0, TRUE); + ret = run_command(op, cmd, &dirs, FALSE, 0, TRUE); nvfree(cmd); - if ((ret == 0) && dir) { + if ((ret == 0) && dirs) { - if (directory_exists(op, dir)) { + next = NULL; + + dir = extract_x_path(dirs, &next); + + while (dir) { + + if (directory_exists(op, dir)) { - ui_expert(op, "X %s path '%s' determined from `%s %s`", - name, dir, op->utils[PKG_CONFIG], - pkg_config_cmd); + ui_expert(op, "X %s path '%s' determined from `%s %s`", + name, dir, op->utils[PKG_CONFIG], + pkg_config_cmd); - *path = dir; - return FALSE; + *path = nvstrdup(dir); + + nvfree(dirs); + + return FALSE; + + } else { + ui_warn(op, "You appear to be using a modular X.Org " + "release, but the X %s installation " + "path, '%s', reported by `%s %s` does not exist. " + "Please check your X.Org installation.", + name, dir, op->utils[PKG_CONFIG], pkg_config_cmd); + } - } else { - ui_warn(op, "You appear to be using a modular X.Org " - "release, but the X %s installation " - "path reported by `%s %s` does not exist. " - "Please check your X.Org installation.", - name, op->utils[PKG_CONFIG], pkg_config_cmd); + dir = extract_x_path(dirs, &next); } } - nvfree(dir); + nvfree(dirs); } /* diff --git a/install-from-cwd.c b/install-from-cwd.c index 9e8d78d..d3a8d8b 100644 --- a/install-from-cwd.c +++ b/install-from-cwd.c @@ -95,9 +95,8 @@ int install_from_cwd(Options *op) if ((p = parse_manifest(op)) == NULL) goto failed; - ui_set_title(op, "%s (%d.%d-%d)", p->description, - p->major, p->minor, p->patch); - + ui_set_title(op, "%s (%s)", p->description, p->version); + /* check that we are not running any X server */ if (!check_for_running_x(op)) goto failed; @@ -240,10 +239,10 @@ int install_from_cwd(Options *op) if (op->kernel_module_only) { ui_message(op, "Installation of the kernel module for the %s " "(version %s) is now complete.", - p->description, p->version_string); + p->description, p->version); } else { ui_message(op, "Installation of the %s (version: %s) is now " - "complete. %s", p->description, p->version_string, msg); + "complete. %s", p->description, p->version, msg); } return TRUE; @@ -405,7 +404,7 @@ int add_this_kernel(Options *op) * The first nine lines of the .manifest file are: * * - a description string - * - a version string of the form "major.minor-patch" + * - a version string * - the kernel module file name * - the kernel interface file name * - the kernel module name (what `rmmod` and `modprobe` should use) @@ -433,7 +432,7 @@ static Package *parse_manifest (Options *op) char *buf, *c, *flag , *tmpstr; int done, n, line; int fd, len = 0; - struct stat stat_buf; + struct stat stat_buf, entry_stat_buf; Package *p; char *manifest = MAP_FAILED, *ptr; @@ -464,10 +463,8 @@ static Package *parse_manifest (Options *op) /* the second line is the version */ line++; - 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; + p->version = get_next_line(ptr, &ptr, manifest, len); + if (!p->version) goto invalid_manifest_file; /* new third line is the kernel interface filename */ @@ -698,7 +695,21 @@ static Package *parse_manifest (Options *op) if (p->entries[n].name) p->entries[n].name++; if (!p->entries[n].name) p->entries[n].name = p->entries[n].file; - + + /* + * store the inode and device information, so that we can + * later recognize it, to avoid accidentally moving it as + * part of the 'find_conflicting_files' path + */ + + if (stat(p->entries[n].file, &entry_stat_buf) != -1) { + p->entries[n].inode = entry_stat_buf.st_ino; + p->entries[n].device = entry_stat_buf.st_dev; + } else { + p->entries[n].inode = 0; + p->entries[n].device = 0; + } + /* free the line */ free(buf); @@ -731,3 +742,48 @@ static Package *parse_manifest (Options *op) return NULL; } /* parse_manifest() */ + + + +/* + * add_package_entry() - add a PackageEntry to the package's entries + * array. + */ + +void add_package_entry(Package *p, + char *file, + char *path, + char *name, + char *target, + char *dst, + unsigned int flags, + mode_t mode) +{ + int n; + struct stat stat_buf; + + n = p->num_entries; + + p->entries = + (PackageEntry *) nvrealloc(p->entries, (n + 1) * sizeof(PackageEntry)); + + p->entries[n].file = file; + p->entries[n].path = path; + p->entries[n].name = name; + p->entries[n].target = target; + p->entries[n].dst = dst; + p->entries[n].flags = flags; + p->entries[n].mode = mode; + + if (stat(p->entries[n].file, &stat_buf) != -1) { + p->entries[n].inode = stat_buf.st_ino; + p->entries[n].device = stat_buf.st_dev; + } else { + p->entries[n].inode = 0; + p->entries[n].device = 0; + } + + p->num_entries++; + +} /* add_package_entry() */ + @@ -816,50 +816,6 @@ int load_kernel_module(Options *op, Package *p) - - - -/* - * check_kernel_module_version() - check that the driver version - * indicated in the /proc filesystem is the same as the driver version - * specified in the package description. - */ - -int check_kernel_module_version(Options *op, Package *p) -{ - int major, minor, patch; - int proc_major, proc_minor, proc_patch; - FILE *fp = 0; - char *buf; - 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); - return FALSE; - } - - if (!nvid_version(p->version_string, &major, &minor, &patch)) { - return FALSE; - } - - if ((proc_major != major) || - (proc_minor != minor) || - (proc_patch != patch)) { - return FALSE; - } - - return TRUE; - -} /* check_kernel_module_version() */ - - - /* * check_for_unloaded_kernel_module() - test if any of the "bad" * kernel modules are loaded; if they are, then try to unload it. If @@ -1331,7 +1287,7 @@ download_updated_kernel_interface(Options *op, Package *p, tmpfile = nvstrcat(op->tmpdir, "/nv-updates-XXXXXX", NULL); url = nvstrcat(op->ftp_site, "/XFree86/", INSTALLER_OS, "-", - INSTALLER_ARCH, "/", p->version_string, + INSTALLER_ARCH, "/", p->version, "/updates/updates.txt", NULL); /* @@ -1395,7 +1351,7 @@ download_updated_kernel_interface(Options *op, Package *p, nvfree(url); url = nvstrcat(op->ftp_site, "/XFree86/", INSTALLER_OS, "-", INSTALLER_ARCH, "/", - p->version_string, "/updates/", buf, NULL); + p->version, "/updates/", buf, NULL); dstfile = nvstrcat(p->precompiled_kernel_interface_directory, "/", buf, NULL); @@ -1428,7 +1384,7 @@ download_updated_kernel_interface(Options *op, Package *p, info = precompiled_unpack(op, dstfile, output_filename, proc_version_string, - p->major, p->minor, p->patch); + p->version); /* compare checksums */ @@ -1654,7 +1610,7 @@ static PrecompiledInfo *scan_dir(Options *op, Package *p, info = precompiled_unpack(op, filename, output_filename, proc_version_string, - p->major, p->minor, p->patch); + p->version); if (info) break; @@ -36,7 +36,6 @@ int build_kernel_module (Options*, Package*); int build_kernel_interface (Options*, Package*); int test_kernel_module (Options*, Package*); int load_kernel_module (Options*, Package*); -int check_kernel_module_version (Options*, Package*); int check_for_unloaded_kernel_module (Options*, Package*); int find_precompiled_kernel_interface (Options*, Package *); char *get_kernel_name (Options*); @@ -1005,51 +1005,6 @@ static char *find_system_util(const char *util) /* - * nvid_version() - parse the given nvid string for the version - * number, and assign major, minor and patch. Returns TRUE on - * success, FALSE on failure. - * - * The version format is assumed to be: is X.Y-ZZZZ - */ - -int nvid_version (const char *str, int *major, int *minor, int *patch) -{ - char *s, *x; - int ret = FALSE; - - s = nvstrdup(str); - x = s; - - while (*x) { - if (((x[0]) && isdigit(x[0])) && - ((x[1]) && (x[1] == '.')) && - ((x[2]) && isdigit(x[2])) && - ((x[3]) && (x[3] == '-')) && - ((x[4]) && isdigit(x[4])) && - ((x[5]) && isdigit(x[5])) && - ((x[6]) && isdigit(x[6])) && - ((x[7]) && isdigit(x[7]))) { - - x[1] = x[3] = x[8] = '\0'; - - *major = atoi(&x[0]); - *minor = atoi(&x[2]); - *patch = atoi(&x[4]); - - ret = TRUE; - break; - } - x++; - } - - free(s); - return ret; - -} /* nvid_version() */ - - - -/* * continue_after_error() - tell the user that an error has occured, * and ask them if they would like to continue. * @@ -1082,10 +1037,10 @@ int do_install(Options *op, Package *p, CommandList *c) char *msg; int len, ret; - len = strlen(p->description) + strlen(p->version_string) + 64; + len = strlen(p->description) + strlen(p->version) + 64; msg = (char *) nvalloc(len); snprintf(msg, len, "Installing '%s' (%s):", - p->description, p->version_string); + p->description, p->version); ret = execute_command_list(op, c, msg, "Installing"); @@ -1102,6 +1057,175 @@ int do_install(Options *op, Package *p, CommandList *c) /* + * extract_version_string() - extract the NVIDIA driver version string + * from the given string. On failure, return NULL; on success, return + * a malloced string containing just the version string. + * + * The version string can have one of two forms: either the old + * "X.Y.ZZZZ" format (e.g., "1.0-9742"), or the new format where it is + * just a collection of period-separated numbers (e.g., "105.17.2"). + * The length and number of periods in the newer format is arbitrary. + * + * Furthermore, we expect the new version format to be enclosed either + * in parenthesis or whitespace (or be at the start or end of the + * input string) and be atleast 5 characters long. This allows us to + * distinguish the version string from other numbers such as the year + * or the old version format in input strings like this: + * + * "NVIDIA UNIX x86 Kernel Module 105.17.2 Fri Dec 15 09:54:45 PST 2006" + * "1.0-105917 (105.9.17)" + */ + +char *extract_version_string(const char *str) +{ + char c, *copiedString, *start, *end, *x, *version = NULL; + int state; + + if (!str) return NULL; + + copiedString = strdup(str); + x = copiedString; + + /* + * look for a block of only numbers and periods; the version + * string must be surrounded by either whitespace, or the + * start/end of the string; we use a small state machine to parse + * the string + */ + + start = NULL; + end = NULL; + +#define STATE_IN_VERSION 0 +#define STATE_NOT_IN_VERSION 1 +#define STATE_LOOKING_FOR_VERSION 2 +#define STATE_FOUND_VERSION 3 + + state = STATE_LOOKING_FOR_VERSION; + + while (*x) { + + c = *x; + + switch (state) { + + /* + * if we are LOOKING_FOR_VERSION, then finding a digit + * will put us inside the version, whitespace (or open + * parenthesis) will allow us to continue to look for the + * version, and any other character will cause us to stop + * looking for the version string + */ + + case STATE_LOOKING_FOR_VERSION: + if (isdigit(c)) { + start = x; + state = STATE_IN_VERSION; + } else if (isspace(c) || (c == '(')) { + state = STATE_LOOKING_FOR_VERSION; + } else { + state = STATE_NOT_IN_VERSION; + } + break; + + /* + * if we are IN_VERSION, then a digit or period will keep + * us in the version, space (or close parenthesis) and + * more than 4 characters of version means we found the + * entire version string. If we find any other character, + * then what we thought was the version string wasn't, so + * move to NOT_IN_VERSION. + */ + + case STATE_IN_VERSION: + if (isdigit(c) || (c == '.')) { + state = STATE_IN_VERSION; + } else if ((isspace(c) || (c == ')')) && ((x - start) >= 5)) { + end = x; + state = STATE_FOUND_VERSION; + goto exit_while_loop; + } else { + state = STATE_NOT_IN_VERSION; + } + break; + + /* + * if we are NOT_IN_VERSION, then space or open + * parenthesis will make us start looking for the version, + * and any other character just leaves us in the + * NOT_IN_VERSION state + */ + + case STATE_NOT_IN_VERSION: + if (isspace(c) || (c == '(')) { + state = STATE_LOOKING_FOR_VERSION; + } else { + state = STATE_NOT_IN_VERSION; + } + break; + } + + x++; + } + + /* + * the NULL terminator that broke us out of the while loop could + * be the end of the version string + */ + + if ((state == STATE_IN_VERSION) && ((x - start) >= 5)) { + end = x; + state = STATE_FOUND_VERSION; + } + + exit_while_loop: + + /* if we found a version string above, copy it */ + + if (state == STATE_FOUND_VERSION) { + *end = '\0'; + version = strdup(start); + goto done; + } + + + + /* + * we did not find a version string with the new format; look for + * a version of the old X.Y-ZZZZ format + */ + + x = copiedString; + + while (*x) { + if (((x[0]) && isdigit(x[0])) && + ((x[1]) && (x[1] == '.')) && + ((x[2]) && isdigit(x[2])) && + ((x[3]) && (x[3] == '-')) && + ((x[4]) && isdigit(x[4])) && + ((x[5]) && isdigit(x[5])) && + ((x[6]) && isdigit(x[6])) && + ((x[7]) && isdigit(x[7]))) { + + x[8] = '\0'; + + version = strdup(x); + goto done; + } + x++; + } + + done: + + free(copiedString); + + return version; + +} /* extract_version_string() */ + + + +/* * should_install_opengl_headers() - if in expert mode, ask the user * if they want to install OpenGL header files. */ @@ -103,7 +103,7 @@ int find_module_utils(Options *op); int check_selinux(Options *op); int check_proc_modprobe_path(Options *op); int check_development_tools(Options *op, Package *p); -int nvid_version (const char *str, int *major, int *minor, int *patch); +char *extract_version_string(const char *str); int continue_after_error(Options *op, const char *fmt, ...); int do_install(Options *op, Package *p, CommandList *c); void should_install_opengl_headers(Options *op, Package *p); diff --git a/mkprecompiled.c b/mkprecompiled.c index d8d11d3..e1f23d5 100644 --- a/mkprecompiled.c +++ b/mkprecompiled.c @@ -14,13 +14,7 @@ * * -i, --interface=<filename> * -o, --output=<filename> - * - * --major-version=<major> - * --minor-version=<minor> - * --patch-version=<patch> - * * -u, --unpack=<filename> - * * -d, --description=<kernel description> * * There is nothing specific to the NVIDIA graphics driver in this @@ -32,12 +26,10 @@ * the first 8 bytes are: "NVIDIA " * * the next 4 bytes (unsigned) are: CRC of the kernel interface module + * + * the next 4 bytes (unsigned) are: the length of the version string (v) * - * the next 4 bytes (unsigned) are: major version - * - * the next 4 bytes (unsigned) are: minor version - * - * the next 4 bytes (unsigned) are: patch version + * the next v bytes are the version string * * the next 4 bytes (unsigned) are: the length of the description (n) * @@ -70,7 +62,7 @@ #define _GNU_SOURCE /* XXX not portable */ #include <getopt.h> -#define CONSTANT_LENGTH (8 + 4 + 12 + 4 + 4) +#define CONSTANT_LENGTH (8 + 4 + 4 + 4 + 4) typedef unsigned int uint32; typedef unsigned char uint8; @@ -85,9 +77,7 @@ typedef struct { char *unpack; char *description; char *proc_version_string; - uint32 major; - uint32 minor; - uint32 patch; + char *version; uint8 info; uint8 match; } Options; @@ -241,10 +231,8 @@ void print_help(void) printf("-v, --proc-version=<string>\n"); printf(" /proc/version string for target kernel.\n\n"); - printf("--major=<major version number>\n"); - printf("--minor=<minor version number>\n"); - printf("--patch=<patch version number>\n\n"); - + printf("--version=<version string>\n\n"); + printf("--info\n"); printf(" Print the description and version number of the file\n"); printf(" specified by the unpack option.\n\n"); @@ -271,9 +259,6 @@ Options *parse_commandline(int argc, char *argv[]) Options *op; int c, option_index = 0; -#define MAJOR_VERSION_OPTION 1 -#define MINOR_VERSION_OPTION 2 -#define PATCH_VERSION_OPTION 3 #define INFO_OPTION 4 static struct option long_options[] = { @@ -283,9 +268,7 @@ Options *parse_commandline(int argc, char *argv[]) { "description", 1, 0, 'd' }, { "help", 0, 0, 'h' }, { "proc-version", 1, 0, 'v' }, - { "major", 1, 0, MAJOR_VERSION_OPTION }, - { "minor", 1, 0, MINOR_VERSION_OPTION }, - { "patch", 1, 0, PATCH_VERSION_OPTION }, + { "version", 1, 0, 'V' }, { "info", 0, 0, INFO_OPTION }, { "match", 0, 0, 'm' }, { 0, 0, 0, 0 } @@ -306,12 +289,7 @@ Options *parse_commandline(int argc, char *argv[]) case 'd': op->description = optarg; break; case 'h': print_help(); exit(0); break; case 'v': op->proc_version_string = optarg; break; - case MAJOR_VERSION_OPTION: - op->major = atoi(optarg); break; - case MINOR_VERSION_OPTION: - op->minor = atoi(optarg); break; - case PATCH_VERSION_OPTION: - op->patch = atoi(optarg); break; + case 'V': op->version = optarg; break; case INFO_OPTION: op->info = 1; break; case 'm': @@ -347,6 +325,11 @@ Options *parse_commandline(int argc, char *argv[]) exit(1); } + if (!op->version) { + fprintf(stderr, "Driver version string not specified.\n"); + exit(1); + } + return op; } /* parse_commandline() */ @@ -482,19 +465,21 @@ int pack(Options *op) int fd, offset, src_fd; uint8 *out, *src, data[4]; uint32 crc; - int description_len, proc_version_len, interface_len, total_len; + int version_len, description_len, proc_version_len; + int interface_len, total_len; /* * get the lengths of the description, the proc version string, * and the interface file. */ + version_len = strlen(op->version); description_len = strlen(op->description); proc_version_len = strlen(op->proc_version_string); interface_len = nv_get_file_length(op->interface); total_len = CONSTANT_LENGTH + - description_len + proc_version_len + interface_len; + version_len + description_len + proc_version_len + interface_len; /* compute the crc of the kernel interface */ @@ -528,17 +513,14 @@ int pack(Options *op) /* write the version */ - encode_uint32(op->major, data); - memcpy(&(out[offset]), data, 4); - offset += 4; - - encode_uint32(op->minor, data); - memcpy(&(out[offset]), data, 4); - offset += 4; - - encode_uint32(op->patch, data); + encode_uint32(version_len, data); memcpy(&(out[offset]), data, 4); offset += 4; + + if (version_len) { + memcpy(&(out[offset]), op->version, version_len); + offset += version_len; + } /* write the description */ @@ -593,8 +575,8 @@ int unpack(Options *op) { int dst_fd, fd, ret, offset, len = 0; char *buf, *dst; - uint32 crc, major, minor, patch, val, size; - char *description, *proc_version_string; + uint32 crc, val, size; + char *version, *description, *proc_version_string; fd = dst_fd = 0; buf = dst = NULL; @@ -635,10 +617,17 @@ int unpack(Options *op) /* read the version */ - major = decode_uint32(buf + offset + 0); - minor = decode_uint32(buf + offset + 4); - patch = decode_uint32(buf + offset + 8); - offset += 12; + val = decode_uint32(buf + offset); + offset += 4; + + if (val > 0) { + version = nv_alloc(val+1); + memcpy(version, buf + offset, val); + version[val] = '\0'; + } else { + version = NULL; + } + offset += val; /* read the description */ @@ -677,7 +666,7 @@ int unpack(Options *op) if (op->info) { printf("description: %s\n", description); - printf("version: %d.%d-%d\n", major, minor, patch); + printf("version: %s\n", version); printf("crc: %u\n", crc); printf("proc version: %s\n", proc_version_string); return 0; diff --git a/nvidia-installer.h b/nvidia-installer.h index c02e887..c686ead 100644 --- a/nvidia-installer.h +++ b/nvidia-installer.h @@ -222,15 +222,21 @@ typedef struct __package_entry { unsigned int flags; mode_t mode; + ino_t inode; + dev_t device; /* + * inode of the file after extraction from the + * package; this is needed to compare against the + * files on the user's system that we consider for + * removal, so that symlink loops don't confuse us + * into deleting the files from the package. + */ } PackageEntry; typedef struct __package { - int major, minor, patch; - char *description; - char *version_string; + char *version; char *kernel_module_filename; char *kernel_interface_filename; char *kernel_module_name; @@ -466,6 +472,14 @@ void log_printf(Options *op, const int wb, int install_from_cwd(Options *op); int add_this_kernel(Options *op); +void add_package_entry(Package *p, + char *file, + char *path, + char *name, + char *target, + char *dst, + unsigned int flags, + mode_t mode); /* XXX */ typedef TextRows *(*FormatTextRows)(const char*, const char*, int, int); diff --git a/precompiled.c b/precompiled.c index ae91390..877f04a 100644 --- a/precompiled.c +++ b/precompiled.c @@ -47,7 +47,7 @@ #include "misc.h" #include "crc.h" -#define PRECOMPILED_CONSTANT_LENGTH (8 + 4 + 12 + 4 + 4) +#define PRECOMPILED_CONSTANT_LENGTH (8 + 4 + 4 + 4 + 4) /* * decode_uint32() - given an index into a buffer, read the next 4 @@ -153,14 +153,12 @@ PrecompiledInfo *precompiled_unpack(Options *op, const char *filename, const char *output_filename, const char *real_proc_version_string, - const int package_major, - const int package_minor, - const int package_patch) + const char *package_version) { int dst_fd, fd, offset, len = 0; char *buf, *dst; - uint32 crc, major, minor, patch, val, size; - char *description, *proc_version_string; + uint32 crc, val, size; + char *version, *description, *proc_version_string; struct stat stat_buf; PrecompiledInfo *info = NULL; @@ -216,17 +214,26 @@ PrecompiledInfo *precompiled_unpack(Options *op, /* read the version */ - major = decode_uint32(buf + offset + 0); - minor = decode_uint32(buf + offset + 4); - patch = decode_uint32(buf + offset + 8); - offset += 12; + val = decode_uint32(buf + offset); + offset += 4; + if ((val + PRECOMPILED_CONSTANT_LENGTH) > size) { + ui_expert(op, "Invalid file '%s' (bad version string length %d).", + filename, val); + goto done; + } + if (val > 0) { + version = nvalloc(val+1); + memcpy(version, buf + offset, val); + version[val] = '\0'; + } else { + version = NULL; + } + offset += val; /* check if this precompiled kernel interface is the right driver version */ - if ((major != package_major) || - (minor != package_minor) || - (patch != package_patch)) { + if (strcmp(version, package_version) != 0) { goto done; } @@ -312,9 +319,7 @@ PrecompiledInfo *precompiled_unpack(Options *op, info = (PrecompiledInfo *) nvalloc(sizeof(PrecompiledInfo)); info->crc = crc; - info->major = major; - info->minor = minor; - info->patch = patch; + info->version = version; info->proc_version_string = proc_version_string; info->description = description; diff --git a/precompiled.h b/precompiled.h index 38bac24..8f784c0 100644 --- a/precompiled.h +++ b/precompiled.h @@ -33,9 +33,7 @@ typedef struct { uint32 crc; - uint32 major; - uint32 minor; - uint32 patch; + char *version; char *proc_version_string; char *description; @@ -48,9 +46,7 @@ PrecompiledInfo *precompiled_unpack(Options *op, const char *filename, const char *output_filename, const char *real_proc_version_string, - const int package_major, - const int package_minor, - const int package_patch); + const char *package_version); #endif /* __NVIDIA_INSTALLER_PRECOMPILED_H__ */ @@ -45,14 +45,14 @@ int sanity(Options *op) { - char *descr; - int major, minor, patch; + char *descr, *version; + int ret; /* check that there's a driver installed at all */ - descr = get_installed_driver_version_and_descr(op, &major, &minor, &patch); + ret = get_installed_driver_version_and_descr(op, &version, &descr); - if (!descr) { + if (!ret) { ui_error(op, "Unable to find any installed NVIDIA driver. The sanity " "check feature is only intended to be used with an existing " "NVIDIA driver installation."); @@ -60,9 +60,9 @@ int sanity(Options *op) } ui_message(op, "The currently installed driver is: '%s' " - "(version: %d.%d-%d). nvidia-installer will now check " + "(version: %s). nvidia-installer will now check " "that all installed files still exist.", - descr, major, minor, patch); + descr, version); /* check that all the files are still where we placed them */ @@ -91,11 +91,12 @@ int sanity(Options *op) * etc). */ - ui_message(op, "'%s' (version: %d.%d-%d) appears to be installed " - "correctly.", descr, major, minor, patch); + ui_message(op, "'%s' (version: %s) appears to be installed " + "correctly.", descr, version); nvfree(descr); - + nvfree(version); + return TRUE; } /* sanity() */ @@ -41,8 +41,8 @@ #include "update.h" -static char *get_latest_driver_version_and_filename(Options *op, - int *, int *, int *); +static int get_latest_driver_version_and_filename(Options *op, + char **, char **); @@ -53,26 +53,38 @@ static char *get_latest_driver_version_and_filename(Options *op, int update(Options *op) { - char *descr, *filename, *tmpfile, *url, *cmd; - int x0, y0, z0, x1, y1, z1, ret, fd; - - descr = get_installed_driver_version_and_descr(op, &x0, &y0, &z0); + char *descr = NULL; + char *filename = NULL; + char *tmpfile = NULL; + char *url = NULL; + char *cmd; + char *installedVersion = NULL; + char *latestVersion = NULL; + int fd, installedRet, latestRet, localRet; + int ret = FALSE; + + installedRet = get_installed_driver_version_and_descr(op, + &installedVersion, + &descr); - filename = get_latest_driver_version_and_filename(op, &x1, &y1, &z1); - if (!filename) return FALSE; - - if (descr && !op->force_update) { + latestRet = get_latest_driver_version_and_filename(op, &latestVersion, + &filename); + if (!latestRet) { + goto done; + } + + if (installedRet && !op->force_update) { /* * if the currently installed driver version is the same as * the latest, don't update. */ - - if ((x0 == x1) && (y0 == y1) && (z0 == z1)) { - ui_message(op, "The latest %s (version %d.%d-%d) is already " - "installed.", descr, x0, y0, z0); - nvfree(descr); - return TRUE; + + if (strcmp(installedVersion, latestVersion) == 0) { + ui_message(op, "The latest %s (version %s) is already " + "installed.", descr, installedVersion); + ret = TRUE; + goto done; } } @@ -81,20 +93,19 @@ int update(Options *op) tmpfile = nvstrcat(op->tmpdir, "/nv-update-XXXXXX", NULL); url = nvstrcat(op->ftp_site, "/XFree86/", INSTALLER_OS, "-", INSTALLER_ARCH, "/", filename, NULL); - nvfree(filename); - + /* create the temporary file */ if ((fd = mkstemp(tmpfile)) == -1) { ui_error(op, "Unable to create temporary file (%s)", strerror(errno)); - return FALSE; + goto done; } /* download the file */ if (!snarf(op, url, fd, SNARF_FLAGS_STATUS_BAR)) { ui_error(op, "Unable to download driver %s.", url); - return FALSE; + goto done; } close(fd); @@ -104,12 +115,12 @@ int update(Options *op) /* check the binary */ cmd = nvstrcat("sh ", tmpfile, " --check", NULL); - ret = run_command(op, cmd, NULL, FALSE, FALSE, TRUE); + localRet = run_command(op, cmd, NULL, FALSE, FALSE, TRUE); nvfree(cmd); - if (ret != 0) { - ui_error(op, "The downloaded file does not pass its integrety check."); - return FALSE; + if (localRet != 0) { + ui_error(op, "The downloaded file does not pass its integrity check."); + goto done; } /* @@ -122,7 +133,7 @@ int update(Options *op) /* execute `sh <downloaded file> <arguments>` */ cmd = nvstrcat("sh ", tmpfile, " ", op->update_arguments, NULL); - ret = system(cmd); + localRet = system(cmd); nvfree(cmd); /* remove the downloaded file */ @@ -134,10 +145,22 @@ int update(Options *op) * function. */ - exit(ret); + exit(localRet); - return TRUE; + ret = TRUE; + + done: + nvfree(installedVersion); + nvfree(descr); + nvfree(latestVersion); + nvfree(filename); + + nvfree(tmpfile); + nvfree(url); + + return ret; + } /* update() */ @@ -148,32 +171,42 @@ int update(Options *op) int report_latest_driver_version(Options *op) { - char *descr, *filename, *url; - int x0, y0, z0, x1, y1, z1; + char *descr = NULL; + char *filename = NULL; + char *url = NULL; + char *installedVersion = NULL; + char *latestVersion = NULL; + int installedRet, latestRet; - descr = get_installed_driver_version_and_descr(op, &x0, &y0, &z0); + installedRet = get_installed_driver_version_and_descr(op, + &installedVersion, + &descr); - filename = get_latest_driver_version_and_filename(op, &x1, &y1, &z1); - - if (!filename) { + latestRet = get_latest_driver_version_and_filename(op, &latestVersion, + &filename); + + if (!latestRet) { nvfree(descr); + nvfree(installedVersion); return FALSE; } url = nvstrcat(op->ftp_site, "/XFree86/", INSTALLER_OS, "-", INSTALLER_ARCH, "/", filename, NULL); - if (descr) { - ui_message(op, "Currently installed version: %d.%d-%d; " - "latest available version: %d.%d-%d; latest driver " - "file: %s.", x0, y0, z0, x1, y1, z1, url); - nvfree(descr); + if (installedRet) { + ui_message(op, "Currently installed version: %s; " + "latest available version: %s; latest driver " + "file: %s.", installedVersion, latestVersion, url); } else { - ui_message(op, "Latest version: %d.%d-%d; latest driver file: %s.", - x1, y1, z1, url); + ui_message(op, "Latest version: %s; latest driver file: %s.", + latestVersion, url); } + nvfree(descr); + nvfree(installedVersion); nvfree(filename); + nvfree(latestVersion); nvfree(url); return TRUE; @@ -216,20 +249,35 @@ char *append_update_arguments(char *s, int c, const char *arg, /* - * get_latest_driver_version() - + * get_latest_driver_version() - download and parse the latest.txt + * file; the format of this file is: + * + * [old format version] [path to .run file] + * [new format version] + * + * This is done for backwards compatibility -- old nvidia-installers + * will read only the first line and parse the old format version + * string; new nvidia-installers will try to find the version string + * on the second line. If we are unable to find the version string on + * the second line, then fall back to the old format string on the + * first line. */ -static char *get_latest_driver_version_and_filename(Options *op, int *major, - int *minor, int *patch) +static int get_latest_driver_version_and_filename(Options *op, + char **pVersion, + char **pFileName) { int fd = -1; int length; + int ret = FALSE; char *tmpfile = NULL; char *url = NULL; char *str = (void *) -1; char *s = NULL; char *buf = NULL; - char *filename = NULL; + char *buf2 = NULL; + char *ptr; + char *version = NULL; struct stat stat_buf; tmpfile = nvstrcat(op->tmpdir, "/nv-latest-XXXXXX", NULL); @@ -264,10 +312,20 @@ static char *get_latest_driver_version_and_filename(Options *op, int *major, goto done; } - buf = get_next_line(str, NULL, str, length); + + /* + * read in the first two lines from the file; the second line may + * optionally contain a version string with the new format + */ + + buf = get_next_line(str, &ptr, str, length); + buf2 = get_next_line(ptr, NULL, str, length); - if (!nvid_version(buf, major, minor, patch)) { - ui_error(op, "Unable to determine latest NVIDIA %s-%s driver " + version = extract_version_string(buf2); + if (!version) version = extract_version_string(buf); + + if (!version) { + ui_error(op, "Unable to determine latest NVIDIA driver " "version (no version number found in %s)", url); goto done; } @@ -281,19 +339,24 @@ static char *get_latest_driver_version_and_filename(Options *op, int *major, } s++; - filename = nvstrdup(s); + *pFileName = nvstrdup(s); + *pVersion = strdup(version); + + ret = TRUE; done: - if (buf) nvfree(buf); + nvfree(buf); + nvfree(buf2); if (str != (void *) -1) munmap(str, stat_buf.st_size); if (fd != -1) close(fd); unlink(tmpfile); - if (tmpfile) nvfree(tmpfile); - if (url) nvfree(url); + nvfree(tmpfile); + nvfree(url); + nvfree(version); - return filename; + return ret; } /* get_latest_driver_version() */ |