/* * Remove an option. */ void removeoption(const char *name) { struct nvlist *nv, *nvt; char *p, *low, c; const char *n; if ((nv = ht_lookup(opttab, name)) != NULL) { if (options == nv) { options = nv->nv_next; nvfree(nv); } else { nvt = options; while (nvt->nv_next != NULL) { if (nvt->nv_next == nv) { nvt->nv_next = nvt->nv_next->nv_next; nvfree(nv); break; } else nvt = nvt->nv_next; } } } (void)ht_remove(opttab, name); low = emalloc(strlen(name) + 1); /* make lowercase, then remove from select table */ for (n = name, p = low; (c = *n) != '\0'; n++) *p++ = isupper(c) ? tolower(c) : c; *p = 0; n = intern(low); free(low); (void)ht_remove(selecttab, n); }
static int get_passive_sock(UrlResource *rsrc, int control) { unsigned char *addr; struct sockaddr_in sa; int sock; int x; char *line, *orig_line; send_control(control, "PASV\r\n", NULL); if( !((line = get_line(rsrc, control)) && check_numeric("227", line)) ) { nvfree(line); return 0; } orig_line = line; if (strlen(line) < 4) { nvfree(line); return 0; } if (!(sock = sock_init(rsrc->op, &sa, control))) return -1; /* skip the numeric response */ line += 4; /* then find the digits */ while (!(isdigit(*line))) line++; /* ugliness from snarf 1.x */ sa.sin_family = AF_INET; addr = (unsigned char *)&sa.sin_addr; for(x = 0; x < 4; x++) { addr[x] = atoi(line); line = strchr(line,',') + 1; } addr = (unsigned char *)&sa.sin_port ; addr[0] = atoi(line); line = strchr(line,',') + 1; addr[1] = atoi(line); if (connect(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) { nvfree(orig_line); ui_error(rsrc->op, "unable to connect (%s)", strerror(errno)); return -1; } nvfree(orig_line); return sock; } /* get_passive_sock() */
/* * Free an expression tree. */ static void expr_free(struct nvlist *expr) { struct nvlist *rhs; /* This loop traverses down the RHS of each subexpression. */ for (; expr != NULL; expr = rhs) { switch (expr->nv_int) { /* Atoms and !-exprs have no left hand side. */ case FX_ATOM: case FX_NOT: break; /* For AND and OR nodes, free the LHS. */ case FX_AND: case FX_OR: expr_free(expr->nv_ptr); break; default: panic("expr_free %d", expr->nv_int); } rhs = expr->nv_next; nvfree(expr); } }
/* * Define an attribute, optionally with an interface (a locator list). * Since an empty locator list is logically different from "no interface", * all locator lists include a dummy head node, which we discard here. */ int defattr(const char *name, struct nvlist *locs) { struct attr *a; struct nvlist *nv; int len; a = emalloc(sizeof *a); if (ht_insert(attrtab, name, a)) { free(a); error("attribute `%s' already defined", name); nvfreel(locs); return (1); } a->a_name = name; if (locs != NULL) { a->a_iattr = 1; a->a_locs = locs->nv_next; nvfree(locs); } else { a->a_iattr = 0; a->a_locs = NULL; } len = 0; for (nv = a->a_locs; nv != NULL; nv = nv->nv_next) len++; a->a_loclen = len; a->a_devs = NULL; a->a_refs = NULL; return (0); }
/* * Iterate over the list of kernel modules from the manifest file; generate * and store module information records for each module in the Package. */ static int parse_kernel_modules_list(Package *p, char *list) { char *name; p->num_kernel_modules = 0; /* in case this gets called more than once */ for (name = strtok(list, " "); name; name = strtok(NULL, " ")) { KernelModuleInfo *module; p->kernel_modules = nvrealloc(p->kernel_modules, (p->num_kernel_modules + 1) * sizeof(p->kernel_modules[0])); module = p->kernel_modules + p->num_kernel_modules; memset(module, 0, sizeof(*module)); module->module_name = nvstrdup(name); module->module_filename = nvstrcat(name, ".ko", NULL); module->has_separate_interface_file = has_separate_interface_file(name); if (module->has_separate_interface_file) { char *core_binary = nvidia_to_nv(name, "-kernel.o_binary"); module->interface_filename = nvidia_to_nv(name, "-linux.o"); module->core_object_name = nvstrcat(name, "/", core_binary, NULL); nvfree(core_binary); } populate_optional_module_info(module); p->num_kernel_modules++; } return p->num_kernel_modules; }
void free_devices(DevicesPtr pDevices) { int i; if (!pDevices) return; for (i = 0; i < pDevices->nDevices; i++) { if (pDevices->devices[i].displayDevices) { nvfree(pDevices->devices[i].displayDevices); } } if (pDevices->devices) { nvfree(pDevices->devices); } nvfree(pDevices); } /* free_devices() */
static int get_sock(UrlResource *rsrc, int control) { struct sockaddr_in sa; unsigned char *addr; unsigned char *port; char *line; char port_string[SNARF_BUFSIZE]; unsigned int sock; socklen_t i; if (!(sock = sock_init(rsrc->op, &sa, control))) return 0; if (listen(sock, 0) < 0) { ui_error(rsrc->op, "unable to listen (%s)", strerror(errno)); return 0; } i = sizeof(sa); getsockname(sock, (struct sockaddr *)&sa, &i); addr = (unsigned char *)(&sa.sin_addr.s_addr); port = (unsigned char *)(&sa.sin_port); sprintf(port_string, "PORT %d,%d,%d,%d,%d,%d\r\n", addr[0], addr[1], addr[2], addr[3], port[0],(unsigned char)port[1]); send_control(control, port_string, NULL); if (!((line = get_line(rsrc, control)) && check_numeric("200", line))) { nvfree(line); return 0; } nvfree(line); return sock; } /* get_sock() */
static void send_control(int sock, char *string, ...) { va_list args; char *line = NULL; char *newline; char *s = NULL; line = nvstrdup(string); va_start(args, string); s = va_arg(args, char *); while (s) { newline = nvstrcat(line, s, NULL); nvfree(line); line = newline; s = va_arg(args, char *); } va_end(args); write(sock, line, strlen(line)); nvfree(line); } /* send_control() */
/* * Read from the given FILE stream until a newline, EOF, or nul * terminator is encountered, writing data into a growable buffer. * The eof parameter is set to TRUE when EOF is encountered. In all * cases, the returned string is null-terminated. * * XXX this function will be rather slow because it uses fgetc() to * pull each character off the stream one at a time; this is done so * that each character can be examined as it's read so that we can * appropriately deal with EOFs and newlines. A better implementation * would use fgets(), but that would still require us to parse each * read line, checking for newlines or guessing if we hit an EOF. */ char *fget_next_line(FILE *fp, int *eof) { char *buf = NULL, *tmpbuf; char *c = NULL; int len = 0, buflen = 0; int ret; const int __fget_next_line_len = 32; if (eof) { *eof = FALSE; } while (1) { if (buflen == len) { /* buffer isn't big enough -- grow it */ buflen += __fget_next_line_len; tmpbuf = nvalloc(buflen); if (buf) { memcpy(tmpbuf, buf, len); nvfree(buf); } buf = tmpbuf; c = buf + len; } ret = fgetc(fp); if ((ret == EOF) && (eof)) { *eof = TRUE; } if ((ret == EOF) || (ret == '\n') || (ret == '\0')) { *c = '\0'; return buf; } *c = (char) ret; len++; c++; } /* while (1) */ return NULL; /* should never get here */ }
/* * Return (possibly in a static buffer) the name of the `source' for a * file. If we have `options source', or if the file is marked `always * source', this is always the path from the `file' line; otherwise we * get the .o from the obj-directory. */ static const char * srcpath(struct files *fi) { /* Always have source, don't support object dirs for kernel builds. */ struct nvlist *nv, *nv1; char *expand, *source; /* Search path list for files we will want to use */ if (fi->fi_nvpath->nv_next == NULL) { nv = fi->fi_nvpath; goto onlyone; } for (nv = fi->fi_nvpath; nv; nv = nv->nv_next) { expand = expandname(nv->nv_name); source = sourcepath(expand ? expand : nv->nv_name); if (access(source, R_OK) == 0) { /* XXX poolalloc() prevents freeing old nv_name */ if (expand) nv->nv_name = intern(expand); break; } free(expand); free(source); } if (nv == NULL) nv = fi->fi_nvpath; /* * Now that we know which path is selected, delete all the * other paths to skip the access() checks next time. */ while ((nv1 = fi->fi_nvpath)) { nv1 = nv1->nv_next; if (fi->fi_nvpath != nv) nvfree(fi->fi_nvpath); fi->fi_nvpath = nv1; } fi->fi_nvpath = nv; nv->nv_next = NULL; onlyone: return (nv->nv_name); }
/* * Add a name=value pair to an option list. The value may be NULL. */ static int do_option(struct hashtab *ht, struct nvlist ***nppp, const char *name, const char *value, const char *type) { struct nvlist *nv; /* assume it will work */ nv = newnv(name, value, NULL, 0, NULL); if (ht_insert(ht, name, nv) == 0) { **nppp = nv; *nppp = &nv->nv_next; return (0); } /* oops, already got that option */ nvfree(nv); if ((nv = ht_lookup(ht, name)) == NULL) panic("do_option"); if (nv->nv_str != NULL) error("already have %s `%s=%s'", type, name, nv->nv_str); else error("already have %s `%s'", type, name); return (1); }
DevicesPtr find_devices(Options *op) { DevicesPtr pDevices = NULL; DisplayDevicePtr pDisplayDevice; int i, j, n, count = 0; unsigned int mask, bit; DeviceRec tmpDevice; NvCfgPciDevice *devs = NULL; NvCfgBool is_primary_device; NvCfgBool ret; char *lib_path; void *lib_handle; NvCfgBool (*__getDevices)(int *n, NvCfgDevice **devs); NvCfgBool (*__openDevice)(int bus, int slot, NvCfgDeviceHandle *handle); NvCfgBool (*__getPciDevices)(int *n, NvCfgPciDevice **devs); NvCfgBool (*__openPciDevice)(int domain, int bus, int slot, int function, NvCfgDeviceHandle *handle); NvCfgBool (*__getNumCRTCs)(NvCfgDeviceHandle handle, int *crtcs); NvCfgBool (*__getProductName)(NvCfgDeviceHandle handle, char **name); NvCfgBool (*__getDisplayDevices)(NvCfgDeviceHandle handle, unsigned int *display_device_mask); NvCfgBool (*__getEDID)(NvCfgDeviceHandle handle, unsigned int display_device, NvCfgDisplayDeviceInformation *info); NvCfgBool (*__isPrimaryDevice)(NvCfgDeviceHandle handle, NvCfgBool *is_primary_device); NvCfgBool (*__closeDevice)(NvCfgDeviceHandle handle); NvCfgBool (*__getDeviceUUID)(NvCfgDeviceHandle handle, char **uuid); /* dlopen() the nvidia-cfg library */ #define __LIB_NAME "libnvidia-cfg.so.1" if (op->nvidia_cfg_path) { lib_path = nvstrcat(op->nvidia_cfg_path, "/", __LIB_NAME, NULL); } else { lib_path = strdup(__LIB_NAME); } lib_handle = dlopen(lib_path, RTLD_NOW); nvfree(lib_path); if (!lib_handle) { nv_warning_msg("error opening %s: %s.", __LIB_NAME, dlerror()); return NULL; } #define __GET_FUNC(proc, name) \ (proc) = dlsym(lib_handle, (name)); \ if (!(proc)) { \ nv_warning_msg("error retrieving symbol %s from %s: %s", \ (name), __LIB_NAME, dlerror()); \ dlclose(lib_handle); \ return NULL; \ } /* required functions */ __GET_FUNC(__getDevices, "nvCfgGetDevices"); __GET_FUNC(__openDevice, "nvCfgOpenDevice"); __GET_FUNC(__getPciDevices, "nvCfgGetPciDevices"); __GET_FUNC(__openPciDevice, "nvCfgOpenPciDevice"); __GET_FUNC(__getNumCRTCs, "nvCfgGetNumCRTCs"); __GET_FUNC(__getProductName, "nvCfgGetProductName"); __GET_FUNC(__getDisplayDevices, "nvCfgGetDisplayDevices"); __GET_FUNC(__getEDID, "nvCfgGetEDID"); __GET_FUNC(__closeDevice, "nvCfgCloseDevice"); __GET_FUNC(__getDeviceUUID, "nvCfgGetDeviceUUID"); /* optional functions */ __isPrimaryDevice = dlsym(lib_handle, "nvCfgIsPrimaryDevice"); if (__getPciDevices(&count, &devs) != NVCFG_TRUE) { return NULL; } if (count == 0) return NULL; pDevices = nvalloc(sizeof(DevicesRec)); pDevices->devices = nvalloc(sizeof(DeviceRec) * count); pDevices->nDevices = count; for (i = 0; i < count; i++) { pDevices->devices[i].dev = devs[i]; if (__openPciDevice(devs[i].domain, devs[i].bus, devs[i].slot, 0, &(pDevices->devices[i].handle)) != NVCFG_TRUE) { goto fail; } if (__getNumCRTCs(pDevices->devices[i].handle, &pDevices->devices[i].crtcs) != NVCFG_TRUE) { goto fail; } if (__getProductName(pDevices->devices[i].handle, &pDevices->devices[i].name) != NVCFG_TRUE) { /* This call may fail with little impact to the Device section */ pDevices->devices[i].name = NULL; } if (__getDeviceUUID(pDevices->devices[i].handle, &pDevices->devices[i].uuid) != NVCFG_TRUE) { goto fail; } if (__getDisplayDevices(pDevices->devices[i].handle, &mask) != NVCFG_TRUE) { goto fail; } pDevices->devices[i].displayDeviceMask = mask; /* count the number of display devices */ for (n = j = 0; j < 32; j++) { if (mask & (1 << j)) n++; } pDevices->devices[i].nDisplayDevices = n; if (n) { /* allocate the info array of the right size */ pDevices->devices[i].displayDevices = nvalloc(sizeof(DisplayDeviceRec) * n); /* fill in the info array */ for (n = j = 0; j < 32; j++) { bit = 1 << j; if (!(bit & mask)) continue; pDisplayDevice = &pDevices->devices[i].displayDevices[n]; pDisplayDevice->mask = bit; if (__getEDID(pDevices->devices[i].handle, bit, &pDisplayDevice->info) != NVCFG_TRUE) { pDisplayDevice->info_valid = FALSE; } else { pDisplayDevice->info_valid = TRUE; } n++; } } else { pDevices->devices[i].displayDevices = NULL; } if ((i != 0) && (__isPrimaryDevice != NULL) && (__isPrimaryDevice(pDevices->devices[i].handle, &is_primary_device) == NVCFG_TRUE) && (is_primary_device == NVCFG_TRUE)) { memcpy(&tmpDevice, &pDevices->devices[0], sizeof(DeviceRec)); memcpy(&pDevices->devices[0], &pDevices->devices[i], sizeof(DeviceRec)); memcpy(&pDevices->devices[i], &tmpDevice, sizeof(DeviceRec)); } ret = __closeDevice(pDevices->devices[i].handle); pDevices->devices[i].handle = NULL; if (ret != NVCFG_TRUE) { goto fail; } } goto done; fail: nv_warning_msg("Unable to use the nvidia-cfg library to query NVIDIA " "hardware."); for (i = 0; i < pDevices->nDevices; i++) { /* close the opened device */ if (pDevices->devices[i].handle) { __closeDevice(pDevices->devices[i].handle); } } free_devices(pDevices); pDevices = NULL; /* fall through */ done: if (devs) free(devs); return pDevices; } /* find_devices() */
char *nv_prepend_to_string_list(char *list, const char *item, const char *delim) { char *new_list = nvstrcat(item, list ? delim : NULL, list, NULL); nvfree(list); return new_list; }
static int enable_separate_x_screens(Options *op, XConfigPtr config, XConfigLayoutPtr layout) { XConfigScreenPtr screen, *screenlist = NULL; XConfigAdjacencyPtr adj; int* screens_to_clone = NULL; int i, nscreens = 0; int have_busids; /* step 1: build the list of screens that are candidate to be cloned */ if (op->screen) { screen = xconfigFindScreen(op->screen, config->screens); if (!screen) { nv_error_msg("Unable to find screen '%s'.", op->screen); return FALSE; } screenlist = nvalloc(sizeof(XConfigScreenPtr)); screenlist[0] = screen; nscreens = 1; } else { for (adj = layout->adjacencies; adj; adj = adj->next) { nscreens++; screenlist = realloc(screenlist, sizeof(XConfigScreenPtr) * nscreens); screenlist[nscreens-1] = adj->screen; } } if (!nscreens) return FALSE; /* step 2: do all screens in the list have a bus ID? */ have_busids = TRUE; for (i = 0; i < nscreens; i++) { if (screenlist[i] && screenlist[i]->device && screenlist[i]->device->busid) { // this screen has a busid } else { have_busids = FALSE; break; } } /* * if not everyone has a bus id, then let's assign bus ids to all * the screens; XXX what if _some_ already have busids? Too bad, * we're going to reassign all of them. */ if (!have_busids) { DevicesPtr pDevices; pDevices = find_devices(op); if (!pDevices) { nv_error_msg("Unable to determine number or location of " "GPUs in system; cannot " "honor '--separate-x-screens' option."); return FALSE; } for (i = 0; i < nscreens; i++) { if (i >= pDevices->nDevices) { /* * we have more screens than GPUs, this screen is no * longer a candidate */ screenlist[i] = NULL; continue; } screenlist[i]->device->busid = nvalloc(32); xconfigFormatPciBusString(screenlist[i]->device->busid, 32, pDevices->devices[i].dev.domain, pDevices->devices[i].dev.bus, pDevices->devices[i].dev.slot, 0); screenlist[i]->device->board = nvstrdup(pDevices->devices[i].name); } free_devices(pDevices); } /* step 3 */ clean_screen_list(screenlist, config, nscreens); /* step 4 */ screens_to_clone = get_screens_to_clone(op, screenlist, nscreens); /* step 5: clone each eligible screen */ for (i = 0; i < nscreens; i++) { if (!screenlist[i]) continue; while (--screens_to_clone[i] > 0) { clone_screen(screenlist[i], screens_to_clone[i]); } } nvfree(screens_to_clone); /* step 6: wipe the existing adjacencies and recreate them */ xconfigFreeAdjacencyList(&layout->adjacencies); create_adjacencies(op, config, layout); /* free unused device and monitor sections */ free_unused_devices(op, config); free_unused_monitors(op, config); /* free stuff */ free(screenlist); return TRUE; } /* enable_separate_x_screens() */
static Package *parse_manifest (Options *op) { char *buf, *c, *tmpstr; int line; int fd, ret, len = 0; struct stat stat_buf; Package *p; char *manifest = MAP_FAILED, *ptr; int opengl_files_packaged = FALSE; p = (Package *) nvalloc(sizeof (Package)); /* open the manifest file */ if ((fd = open(".manifest", O_RDONLY)) == -1) { ui_error(op, "No package found for installation. Please run " "this utility with the '--help' option for usage " "information."); goto fail; } if (fstat(fd, &stat_buf) == -1) goto cannot_open; len = stat_buf.st_size; manifest = mmap(0, len, PROT_READ, MAP_FILE|MAP_SHARED, fd, 0); if (manifest == MAP_FAILED) goto cannot_open; /* the first line is the description */ line = 1; 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 = get_next_line(ptr, &ptr, manifest, len); if (!p->version) goto invalid_manifest_file; /* Ignore the third line */ line++; nvfree(get_next_line(ptr, &ptr, manifest, len)); /* the fourth line is the list of kernel modules. */ line++; tmpstr = get_next_line(ptr, &ptr, manifest, len); if (parse_kernel_modules_list(p, tmpstr) == 0) { goto invalid_manifest_file; } nvfree(tmpstr); /* * set the default value of excluded_kernel_modules to an empty, heap * allocated string so that it can be freed and won't prematurely end * an nvstrcat()ed string when unset. */ p->excluded_kernel_modules = nvstrdup(""); /* * ignore the fifth and sixth lines */ line++; nvfree(get_next_line(ptr, &ptr, manifest, len)); line++; nvfree(get_next_line(ptr, &ptr, manifest, len)); /* the seventh line is the kernel module build directory */ line++; p->kernel_module_build_directory = get_next_line(ptr, &ptr, manifest, len); if (!p->kernel_module_build_directory) goto invalid_manifest_file; remove_trailing_slashes(p->kernel_module_build_directory); /* * the eigth line is the directory containing precompiled kernel * interfaces */ line++; p->precompiled_kernel_interface_directory = get_next_line(ptr, &ptr, manifest, len); if (!p->precompiled_kernel_interface_directory) goto invalid_manifest_file; remove_trailing_slashes(p->precompiled_kernel_interface_directory); /* the rest of the file is file entries */ line++; for (; (buf = get_next_line(ptr, &ptr, manifest, len)); line++) { char *flag = NULL; PackageEntry entry; int entry_success = FALSE; if (buf[0] == '\0') { free(buf); break; } /* initialize the new entry */ memset(&entry, 0, sizeof(PackageEntry)); /* read the file name and permissions */ c = buf; entry.file = read_next_word(buf, &c); if (!entry.file) goto entry_done; tmpstr = read_next_word(c, &c); if (!tmpstr) goto entry_done; /* translate the mode string into an octal mode */ ret = mode_string_to_mode(op, tmpstr, &entry.mode); free(tmpstr); if (!ret) goto entry_done; /* every file has a type field */ entry.type = FILE_TYPE_NONE; flag = read_next_word(c, &c); if (!flag) goto entry_done; entry.type = parse_manifest_file_type(flag, &entry.caps); if (entry.type == FILE_TYPE_NONE) { goto entry_done; } /* Track whether certain file types were packaged */ switch (entry.type) { case FILE_TYPE_XMODULE_SHARED_LIB: op->x_files_packaged = TRUE; break; default: break; } /* set opengl_files_packaged if any OpenGL files were packaged */ if (entry.caps.is_opengl) { opengl_files_packaged = TRUE; } /* some libs/symlinks have an arch field */ entry.compat_arch = FILE_COMPAT_ARCH_NONE; if (entry.caps.has_arch) { nvfree(flag); flag = read_next_word(c, &c); if (!flag) goto entry_done; if (strcmp(flag, "COMPAT32") == 0) entry.compat_arch = FILE_COMPAT_ARCH_COMPAT32; else if (strcmp(flag, "NATIVE") == 0) entry.compat_arch = FILE_COMPAT_ARCH_NATIVE; else { goto entry_done; } } /* if compat32 files are packaged, set compat32_files_packaged */ if (entry.compat_arch == FILE_COMPAT_ARCH_COMPAT32) { op->compat32_files_packaged = TRUE; } /* some libs/symlinks have a class field */ entry.tls_class = FILE_TLS_CLASS_NONE; if (entry.caps.has_tls_class) { nvfree(flag); flag = read_next_word(c, &c); if (!flag) goto entry_done; if (strcmp(flag, "CLASSIC") == 0) entry.tls_class = FILE_TLS_CLASS_CLASSIC; else if (strcmp(flag, "NEW") == 0) entry.tls_class = FILE_TLS_CLASS_NEW; else { goto entry_done; } } /* some file types have a path field, or inherit their paths */ if (entry.caps.has_path) { entry.path = read_next_word(c, &c); if (!entry.path) goto invalid_manifest_file; } else if (entry.caps.inherit_path) { int i; char *path, *depth, *slash; const char * const depth_marker = "INHERIT_PATH_DEPTH:"; depth = read_next_word(c, &c); if (!depth || strncmp(depth, depth_marker, strlen(depth_marker)) != 0) { goto invalid_manifest_file; } entry.inherit_path_depth = atoi(depth + strlen(depth_marker)); nvfree(depth); /* Remove the file component from the packaged filename */ path = entry.path = nvstrdup(entry.file); slash = strrchr(path, '/'); if (slash == NULL) { goto invalid_manifest_file; } slash[1] = '\0'; /* Strip leading directory components from the path */ for (i = 0; i < entry.inherit_path_depth; i++) { slash = strchr(entry.path, '/'); if (slash == NULL) { goto invalid_manifest_file; } entry.path = slash + 1; } entry.path = nvstrdup(entry.path); nvfree(path); } else { entry.path = NULL; } /* symlinks have a target */ if (entry.caps.is_symlink) { entry.target = read_next_word(c, &c); if (!entry.target) goto invalid_manifest_file; } else { entry.target = NULL; } /* * as a convenience for later, set the 'name' pointer to * the basename contained in 'file' (ie the portion of * 'file' without any leading directory components */ entry.name = strrchr(entry.file, '/'); if (entry.name) entry.name++; if (!entry.name) entry.name = entry.file; add_package_entry(p, entry.file, entry.path, entry.name, entry.target, entry.dst, entry.type, entry.tls_class, entry.compat_arch, entry.mode); entry_success = TRUE; entry_done: /* clean up */ nvfree(buf); nvfree(flag); if (!entry_success) { goto invalid_manifest_file; } } /* If no OpenGL files were packaged, we can't install them. Set the * no_opengl_files flag so that everything we skip when explicitly * excluding OpenGL is also skipped when OpenGL is not packaged. */ if (!opengl_files_packaged) { op->no_opengl_files = TRUE; } munmap(manifest, len); if (fd != -1) close(fd); return p; cannot_open: ui_error(op, "Failure opening package's .manifest file (%s).", strerror(errno)); goto fail; invalid_manifest_file: ui_error(op, "Invalid .manifest file; error on line %d.", line); goto fail; fail: free_package(p); if (manifest != MAP_FAILED) munmap(manifest, len); if (fd != -1) close(fd); return NULL; } /* parse_manifest() */
/* * get_screens_to_clone() - try to detect automatically how many heads has each * device in order to use that number to create more than two separate X * screens. If the user specifies the option --num-x-screens <quantity>, that * value is used. If neither the user specifies the quantity or the number of * heads can be detected automatically, it uses 2 heads (the standard * behavior). This function returns an array of size nscreens with the number * of screens to clone per screen candidate. The caller is responsible of * freeing the memory of that array. */ static int* get_screens_to_clone(Options *op, const XConfigScreenPtr *screen_candidates, int nscreens) { DevicesPtr pDevices; int *screens_to_clone, *supported_screens; int i, j, devs_found; screens_to_clone = nvalloc(nscreens * sizeof(int)); supported_screens = nvalloc(nscreens * sizeof(int)); /* Detect the number of supported screens per screen candidate */ devs_found = FALSE; pDevices = find_devices(op); if (pDevices) { for (i = 0; i < nscreens; i++) { int bus, slot, scratch; if (!screen_candidates[i]) { continue; } /* parse the bus id for this candidate screen */ if (!xconfigParsePciBusString(screen_candidates[i]->device->busid, &bus, &slot, &scratch)) { continue; } for (j = 0; j < pDevices->nDevices; j++) { if ((pDevices->devices[j].dev.bus == bus) && (pDevices->devices[j].dev.slot == slot)) { if (pDevices->devices[j].crtcs > 0) { supported_screens[i] = pDevices->devices[j].crtcs; } break; } } } free_devices(pDevices); devs_found = TRUE; } /* If user has defined a number of screens per GPU, use that value */ if (op->num_x_screens > 0) { for (i = 0; i < nscreens; i++) { if (!screen_candidates[i]) { continue; } /* Print error when user specifies more X screens than supported */ if (devs_found && op->num_x_screens > supported_screens[i]) { nv_warning_msg("Number of X screens specified is higher than the " "supported quantity (%d)", supported_screens[i]); } screens_to_clone[i] = op->num_x_screens; } goto done; } for (i = 0; i < nscreens; i++) { if (screen_candidates[i]) { if (devs_found) { /* If devices found, use the supported screens number */ screens_to_clone[i] = supported_screens[i]; } else { /* Default behavior (2 heads per GPU) */ screens_to_clone[i] = 2; } } } done: nvfree(supported_screens); return screens_to_clone; }
static int assisted_module_signing(Options *op, Package *p) { int generate_keys = FALSE, do_sign = FALSE, secureboot, i; secureboot = secure_boot_enabled(); if (secureboot < 0) { ui_log(op, "Unable to determine if Secure Boot is enabled: %s", strerror(-secureboot)); } if (op->kernel_module_signed) { /* The kernel module is already signed, e.g. from linking a precompiled * interface + appending a detached signature */ return TRUE; } if (test_kernel_config_option(op, p, "CONFIG_DUMMY_OPTION") == KERNEL_CONFIG_OPTION_UNKNOWN) { /* Unable to test kernel configuration options, possibly due to * missing kernel headers. Since we might be installing on a * system that doesn't have the headers, bail out. */ return TRUE; } if (op->module_signing_secret_key && op->module_signing_public_key) { /* If the user supplied signing keys, sign the module, regardless of * whether or not we actually need to. */ do_sign = TRUE; } else if (test_kernel_config_option(op, p, "CONFIG_MODULE_SIG_FORCE") == KERNEL_CONFIG_OPTION_DEFINED) { /* If CONFIG_MODULE_SIG_FORCE is set, we must sign. */ ui_message(op, "The target kernel has CONFIG_MODULE_SIG_FORCE set, " "which means that it requires that kernel modules be " "cryptographically signed by a trusted key."); do_sign = TRUE; } else if (secureboot != 1 && !op->expert) { /* If this is a non-UEFI system, or a UEFI system with secure boot * disabled, or we are unable to determine whether the system has * secure boot enabled, bail out unless in expert mode. */ return TRUE; } else if (test_kernel_config_option(op, p, "CONFIG_MODULE_SIG") == KERNEL_CONFIG_OPTION_DEFINED){ /* The kernel may or may not enforce module signatures; ask the user * whether to sign the module. */ const char *choices[2] = { "Sign the kernel module", "Install without signing" }; const char* sb_message = (secureboot == 1) ? "This system also has UEFI Secure Boot " "enabled; many distributions enforce " "module signature verification on UEFI " "systems when Secure Boot is enabled. " : ""; do_sign = (ui_multiple_choice(op, choices, 2, 1, "The target kernel " "has CONFIG_MODULE_SIG set, which means " "that it supports cryptographic " "signatures on kernel modules. On some " "systems, the kernel may refuse to load " "modules without a valid signature from " "a trusted key. %sWould you like to sign " "the NVIDIA kernel module?", sb_message) == 0); } if (!do_sign) { /* The user explicitly opted out of module signing, or the kernel does * not support module signatures, and no signing keys were provided; * there is nothing for us to do here. */ return TRUE; } /* If we're missing either key, we need to get both from the user. */ if (!op->module_signing_secret_key || !op->module_signing_public_key) { const char *choices[2] = { "Use an existing key pair", "Generate a new key pair" }; generate_keys = (ui_multiple_choice(op, choices, 2, 1, "Would you like " "to sign the NVIDIA kernel module " "with an existing key pair, or " "would you like to generate a new " "one?") == 1); if (generate_keys) { char *cmdline, *x509_hash, *private_key_path, *public_key_path; int ret, generate_failed = FALSE; if (!op->utils[OPENSSL]) { ui_error(op, "Unable to generate key pair: openssl not " "found!"); return FALSE; } /* Determine what hashing algorithm to use for the generated X.509 * certificate. XXX The default is to use the same hash that is * used for signing modules; the two hashes are actually orthognal * to each other, but by choosing the module signing hash we are * guaranteed that the chosen hash will be built into the kernel. */ if (op->module_signing_x509_hash) { x509_hash = nvstrdup(op->module_signing_x509_hash); } else { char *guess, *guess_trimmed, *warn = NULL; char *no_guess = "Unable to guess the module signing hash."; char *common_warn = "The module signing certificate generated " "by nvidia-installer will be signed with " "sha256 as a fallback. If the resulting " "certificate fails to import into your " "kernel's trusted keyring, please run the " "installer again, and either use a pre-" "generated key pair, or set the " "--module-signing-x509-hash option if you " "plan to generate a new key pair with " "nvidia-installer."; guess = guess_module_signing_hash(op, p->kernel_module_build_directory); if (guess == NULL) { warn = no_guess; goto guess_fail; } guess_trimmed = nv_trim_space(guess); guess_trimmed = nv_trim_char_strict(guess_trimmed, '"'); if (guess_trimmed) { if (strlen(guess_trimmed) == 0) { warn = no_guess; goto guess_fail; } x509_hash = nvstrdup(guess_trimmed); } else { warn = "Error while parsing the detected module signing " "hash."; goto guess_fail; } guess_fail: nvfree(guess); if (warn) { ui_warn(op, "%s %s", warn, common_warn); x509_hash = nvstrdup("sha256"); } } log_printf(op, NULL, "Generating key pair for module signing..."); /* Generate temporary files for the signing key and certificate */ private_key_path = write_temp_file(op, 0, NULL, 0600); public_key_path = write_temp_file(op, 0, NULL, 0644); if (!private_key_path || !public_key_path) { ui_error(op, "Failed to create one or more temporary files for " "the module signing keys."); generate_failed = TRUE; goto generate_done; } /* Generate a key pair using openssl. * XXX We assume that sign-file requires the X.509 certificate * in DER format; if this changes in the future we will need * to be able to accommodate the actual required format. */ cmdline = nvstrcat("cd ", p->kernel_module_build_directory, "; ", op->utils[OPENSSL], " req -new -x509 -newkey " "rsa:2048 -days 7300 -nodes -subj " "\"/CN=nvidia-installer generated signing key/\"" " -keyout ", private_key_path, " -outform DER -out ", public_key_path, " -", x509_hash, NULL); nvfree(x509_hash); ret = run_command(op, cmdline, NULL, TRUE, 8, TRUE); nvfree(cmdline); if (ret != 0) { ui_error(op, "Failed to generate key pair!"); generate_failed = TRUE; goto generate_done; } log_printf(op, NULL, "Signing keys generated successfully."); /* Set the signing keys to the newly generated pair. */ op->module_signing_secret_key = nvstrdup(private_key_path); op->module_signing_public_key = nvstrdup(public_key_path); generate_done: nvfree(private_key_path); nvfree(public_key_path); if (generate_failed) { return FALSE; } } else { /* The user already has keys; prompt for their locations. */ op->module_signing_secret_key = get_filename(op, op->module_signing_secret_key, "Please provide the path to the private key"); op->module_signing_public_key = get_filename(op, op->module_signing_public_key, "Please provide the path to the public key"); } } /* Now that we have keys (user-supplied or installer-generated), * sign the kernel module/s which we built earlier. */ for (i = 0; i < p->num_kernel_modules; i++) { if (!sign_kernel_module(op, p->kernel_module_build_directory, p->kernel_modules[i].module_filename, TRUE)) { return FALSE; } } if (generate_keys) { /* If keys were generated, we should install the verification cert * so that the user can make the kernel trust it, and either delete * or install the private signing key. */ char *name, *result = NULL, *fingerprint, *cmdline; char short_fingerprint[9]; int ret, delete_secret_key; delete_secret_key = ui_yes_no(op, TRUE, "The NVIDIA kernel module was " "successfully signed with a newly " "generated key pair. Would you like to " "delete the private signing key?"); /* Get the fingerprint of the X.509 certificate. We already used openssl to create a keypair at this point, so we know we have it; otherwise, we would have already returned by now. */ cmdline = nvstrcat(op->utils[OPENSSL], " x509 -noout -fingerprint ", "-inform DER -in ", op->module_signing_public_key, NULL); ret = run_command(op, cmdline, &result, FALSE, 0, FALSE); nvfree(cmdline); /* Format: "SHA1 Fingerprint=00:00:00:00:..." */ fingerprint = strchr(result, '=') + 1; if (ret != 0 || !fingerprint || strlen(fingerprint) < 40) { char *sha1sum = find_system_util("sha1sum"); if (sha1sum) { /* the openssl command failed, or we parsed its output * incorrectly; try to get a sha1sum of the DER certificate */ cmdline = nvstrcat(sha1sum, " ", op->module_signing_public_key, NULL); ret = run_command(op, cmdline, &result, FALSE, 0, FALSE); nvfree(sha1sum); nvfree(cmdline); fingerprint = result; } if (!sha1sum || ret != 0 || !fingerprint || strlen(fingerprint) < 40) { /* Unable to determine fingerprint */ fingerprint = "UNKNOWN"; } else { char *end = strchr(fingerprint, ' '); *end = '\0'; } } else { /* Remove any ':' characters from fingerprint and truncate */ char *tmp = nv_strreplace(fingerprint, ":", ""); strncpy(short_fingerprint, tmp, sizeof(short_fingerprint)); nvfree(tmp); } short_fingerprint[sizeof(short_fingerprint) - 1] = '\0'; /* Add the public key to the package */ /* XXX name will be leaked when freeing package */ name = nvstrcat("nvidia-modsign-crt-", short_fingerprint, ".der", NULL); add_package_entry(p, nvstrdup(op->module_signing_public_key), NULL, /* path */ name, NULL, /* target */ NULL, /* dst */ FILE_TYPE_MODULE_SIGNING_KEY, FILE_TLS_CLASS_NONE, FILE_COMPAT_ARCH_NONE, 0444); ui_message(op, "An X.509 certificate containing the public signing " "key will be installed to %s/%s. The SHA1 fingerprint of " "this certificate is: %s.\n\nThis certificate must be " "added to a key database which is trusted by your kernel " "in order for the kernel to be able to verify the module " "signature.", op->module_signing_key_path, name, fingerprint); nvfree(result); /* Delete or install the private key */ if (delete_secret_key) { secure_delete(op, op->module_signing_secret_key); } else { /* Add the private key to the package */ name = nvstrcat("nvidia-modsign-key-", short_fingerprint, ".key", NULL); add_package_entry(p, nvstrdup(op->module_signing_secret_key), NULL, /* path */ name, NULL, /* target */ NULL, /* dst */ FILE_TYPE_MODULE_SIGNING_KEY, FILE_TLS_CLASS_NONE, FILE_COMPAT_ARCH_NONE, 0400); ui_message(op, "The private signing key will be installed to %s/%s. " "After the public key is added to a key database which " "is trusted by your kernel, you may reuse the saved " "public/private key pair to sign additional kernel " "modules, without needing to re-enroll the public key. " "Please take some reasonable precautions to secure the " "private key: see the README for suggestions.", op->module_signing_key_path, name); } } /* if (generate_keys) */ return TRUE; } /* assisted_module_signing() */
static void free_package(Package *p) { int i; if (!p) return; nvfree(p->description); nvfree(p->version); nvfree(p->kernel_module_build_directory); nvfree(p->precompiled_kernel_interface_directory); for (i = 0; i < p->num_kernel_modules; i++) { free_kernel_module_info(p->kernel_modules[i]); } nvfree(p->kernel_modules); nvfree(p->excluded_kernel_modules); for (i = 0; i < p->num_entries; i++) { nvfree(p->entries[i].file); nvfree(p->entries[i].path); nvfree(p->entries[i].target); nvfree(p->entries[i].dst); /* * Note: p->entries[i].name just points into * p->entries[i].file, so don't free p->entries[i].name */ } nvfree((char *) p->entries); nvfree((char *) p); } /* free_package() */
int ftp_transfer(UrlResource *rsrc) { Url *u = NULL; char *line = NULL; int sock = 0; int data_sock = 0; int passive = 1; int retval = 0; u = rsrc->url; /* * first of all, if this is proxied, just pass it off to the * http module, since that's how we support proxying. */ rsrc->proxy = get_proxy("FTP_PROXY"); if (rsrc->proxy && (rsrc->proxy[0] != '\0')) { return http_transfer(rsrc); } ftp_set_defaults(rsrc, u); if (!(sock = tcp_connect(rsrc->op, u->host, u->port))) return FALSE; if (!(line = get_line(rsrc, sock))) return FALSE; if (!check_numeric("220", line)) { ui_error(rsrc->op, "bad ftp server greeting: %s", line); nvfree(line); return FALSE; } send_control(sock, "USER ", u->username, "\r\n", NULL); if (!(line = get_line(rsrc, sock))) return FALSE; /* do the password dance */ if (!check_numeric("230", line)) { if (!check_numeric("331", line)) { ui_error(rsrc->op, "bad/unexpected response: %s", line); nvfree(line); return FALSE; } else { nvfree(line); send_control(sock, "PASS ", u->password, "\r\n", NULL); if (!((line = get_line(rsrc, sock)) && check_numeric("230", line)) ) { nvfree(line); ui_error(rsrc->op, "login failed"); return FALSE; } nvfree(line); } } /* set binmode */ send_control(sock, "TYPE I\r\n", NULL); if (!(line = get_line(rsrc, sock))) return 0; nvfree(line); if (u->path) { send_control(sock, "CWD ", u->path, "\r\n", NULL); if (!((line = get_line(rsrc, sock)) && check_numeric("250", line))) { nvfree(line); close_quit(sock); return 0; } nvfree(line); } /* finally, the good stuff */ /* get a socket for reading. try passive first. */ if ((data_sock = get_passive_sock(rsrc, sock)) == -1) { return FALSE; } if (!data_sock) { if ((data_sock = get_sock(rsrc, sock)) < 1) return 0; else passive = 0; } if (u->file) { send_control(sock, "SIZE ", u->file, "\r\n", NULL); line = get_line(rsrc, sock); if (line && check_numeric("213", line)) { rsrc->outfile_size = atoi(line + 3); } else { rsrc->outfile_size = 0; } } if (u->file) send_control(sock, "RETR ", u->file, "\r\n", NULL); else send_control(sock, "NLST\r\n", NULL); if (!((line = get_line(rsrc, sock)) && (check_numeric("150", line) || check_numeric("125", line)))) { nvfree(line); close_quit(sock); return 0; } if (!passive) data_sock = accept(data_sock, NULL, NULL); nvfree(line); retval = dump_data(rsrc, data_sock); line = get_line(rsrc, sock); /* 226 Transfer complete */ nvfree(line); send_control(sock, "QUIT\r\n", NULL); line = get_line(rsrc, sock); /* 221 Goodbye */ nvfree(line); close(sock); close(data_sock); return retval; } /* ftp_transfer() */