static XConfigScreenPtr clone_screen(XConfigScreenPtr screen0, int idx) { XConfigScreenPtr screen = nvalloc(sizeof(XConfigScreenRec)); screen->identifier = nvasprintf("%s (%d)", screen0->identifier, idx); screen->device = clone_device(screen0->device, idx); screen->device_name = nvstrdup(screen->device->identifier); screen->monitor = screen0->monitor; screen->monitor_name = nvstrdup(screen0->monitor_name); screen->defaultdepth = screen0->defaultdepth; screen->displays = clone_display_list(screen0->displays); screen->options = xconfigOptionListDup(screen0->options); if (screen0->comment) screen->comment = nvstrdup(screen0->comment); /* insert the new screen after the original screen */ screen->next = screen0->next; screen0->next = screen; return screen; } /* clone_screen() */
/* * 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; }
static void create_adjacencies(Options *op, XConfigPtr config, XConfigLayoutPtr layout) { XConfigAdjacencyPtr adj, prev_adj; XConfigScreenPtr screen; int i; i = 0; prev_adj = NULL; for (screen = config->screens; screen; screen = screen->next) { adj = nvalloc(sizeof(XConfigAdjacencyRec)); adj->scrnum = i; adj->screen_name = nvstrdup(screen->identifier); adj->screen = screen; if (prev_adj) { prev_adj->next = adj; } else { layout->adjacencies = adj; } prev_adj = adj; i++; } xconfigGenerateAssignScreenAdjacencies(layout); } /* create_adjacencies() */
static char *create_display_device_target_string(CtrlTarget *t, const ConfigProperties *conf) { char *target_name = NULL; char *target_prefix_name = NULL; char *display_name = NULL; char *s; if (t->protoNames[NV_DPY_PROTO_NAME_RANDR]) { target_name = t->protoNames[NV_DPY_PROTO_NAME_RANDR]; } /* If we don't have a target name here, use the full name and return. */ if (!target_name) { return nvstrdup(t->name); } /* Get the display name if the user requested it to be used. */ if (conf->booleans & CONFIG_PROPERTIES_INCLUDE_DISPLAY_NAME_IN_CONFIG_FILE) { display_name = NvCtrlGetDisplayName(t); } /* Get the target type prefix. */ target_prefix_name = nvstrdup(t->targetTypeInfo->parsed_name); nvstrtoupper(target_prefix_name); /* Build the string */ if (display_name && target_prefix_name) { s = nvasprintf("%s[%s:%s]", display_name, target_prefix_name, target_name); } else if (target_prefix_name) { s = nvasprintf("[%s:%s]", target_prefix_name, target_name); } else if (display_name) { s = nvasprintf("%s[%s]", display_name, target_name); } else { s = nvasprintf("[%s]", target_name); } free(target_prefix_name); free(display_name); return s; }
void ctk_help_data_list_prepend(GList **list, const gchar *label, const gchar *help_text, const gchar *extended_help_text) { CtkHelpDataItem *item; if (!label || !help_text) { return; } item = nvalloc(sizeof(CtkHelpDataItem)); item->label = nvstrdup(label); item->help_text = nvstrdup(help_text); item->extended_help_text = extended_help_text ? nvstrdup(extended_help_text) : NULL; *list = g_list_prepend(*list, item); }
static XConfigDisplayPtr clone_display_list(XConfigDisplayPtr display0) { XConfigDisplayPtr d = NULL, prev = NULL, head = NULL; while (display0) { d = nvalloc(sizeof(XConfigDisplayRec)); memcpy(d, display0, sizeof(XConfigDisplayRec)); if (display0->visual) d->visual = nvstrdup(display0->visual); if (display0->comment) d->comment = nvstrdup(display0->comment); d->options = xconfigOptionListDup(display0->options); d->next = NULL; if (prev) prev->next = d; if (!head) head = d; prev = d; display0 = display0->next; } return head; } /* clone_display_list() */
static XConfigDevicePtr clone_device(XConfigDevicePtr device0, int idx) { XConfigDevicePtr device; device = nvalloc(sizeof(XConfigDeviceRec)); device->identifier = nvasprintf("%s (%d)", device0->identifier, idx); if (device0->vendor) device->vendor = nvstrdup(device0->vendor); if (device0->board) device->board = nvstrdup(device0->board); if (device0->chipset) device->chipset = nvstrdup(device0->chipset); if (device0->busid) device->busid = nvstrdup(device0->busid); if (device0->card) device->card = nvstrdup(device0->card); if (device0->driver) device->driver = nvstrdup(device0->driver); if (device0->ramdac) device->ramdac = nvstrdup(device0->ramdac); if (device0->comment) device->comment = nvstrdup(device0->comment); /* these are needed for multiple X screens on one GPU */ device->screen = idx; device0->screen = 0; device->chipid = -1; device->chiprev = -1; device->irq = -1; device->options = xconfigOptionListDup(device0->options); /* insert the new device after the original device */ device->next = device0->next; device0->next = device; return device; } /* clone_device() */
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() */
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() */
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 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() */