Files
svcmobrel-release 4ece7a7e48 Updating prebuilts and/or headers
22a5c807291792a264b5acca7ff6d199468890b8 - nvidia-xconfig-35.6.2/Makefile
4cc77b90af91e615a64ae04893fdffa7939db84c - nvidia-xconfig-35.6.2/COPYING
f14e9577e537037d4778d490ef70f13b0e94a70a - nvidia-xconfig-35.6.2/option_table.h
647e7896275a1113ec99352d573823a05001f57e - nvidia-xconfig-35.6.2/lscf.c
1e39095238886dfc6a69f7ec750e10c05a93e7d1 - nvidia-xconfig-35.6.2/nvidia-xconfig.1.m4
a5ad539267b73169480e7898b284823639c4db3a - nvidia-xconfig-35.6.2/tree.c
b3d0f9f27c4d9cb7940d04e1dd387d357a16024c - nvidia-xconfig-35.6.2/nvidia-xconfig.c
46f2ea329459b0b16cb36cc14cec0de737d0963e - nvidia-xconfig-35.6.2/options.c
6f6f68f976250f2646450e571f9ab2d7eee1ac80 - nvidia-xconfig-35.6.2/nvidia-cfg.h
913b088cb559f31e09a1baf89d85d75cb43079b4 - nvidia-xconfig-35.6.2/nvidia-xconfig.h
bfa37f78ba458f14a1865bbf3f67eb84987a7e1c - nvidia-xconfig-35.6.2/extract_edids.c
d37da5a118e0418b267a48d05fd144611316b42c - nvidia-xconfig-35.6.2/gen-manpage-opts.c
41bcac41393c9a465c30c07cf1ab386647a16687 - nvidia-xconfig-35.6.2/util.c
9b0c02164398be2795fea7cb13c9e1b062d24bfb - nvidia-xconfig-35.6.2/query_gpu_info.c
c946eefad99cec9366d8abbd4e45c5d138d3b7be - nvidia-xconfig-35.6.2/make_usable.c
10edc2c301fd331439b38d001c0df41669c238b2 - nvidia-xconfig-35.6.2/multiple_screens.c
c7b8d8ca0f7c9dcc2cdca4f8e77d1122c71892ef - nvidia-xconfig-35.6.2/XF86Config-parser/Read.c
a9bc06f33bf525c2b08be2dc3cd64a59c4c7946d - nvidia-xconfig-35.6.2/XF86Config-parser/Configint.h
2022a4a3c2a1b23a67ae74f50a3849f5f3a45e4b - nvidia-xconfig-35.6.2/XF86Config-parser/Keyboard.c
83b0a8efd6a508db54995688ab353591bdb242a2 - nvidia-xconfig-35.6.2/XF86Config-parser/Flags.c
e67d630ef396ab7d34524c333f3a77fc42ba8fc6 - nvidia-xconfig-35.6.2/XF86Config-parser/configProcs.h
f3d611bdbddfa64675a0810ef81dada57e224bcd - nvidia-xconfig-35.6.2/XF86Config-parser/Extensions.c
5ffb2caa5077a2e6ec1c5ece807e71503fb2fbce - nvidia-xconfig-35.6.2/XF86Config-parser/Module.c
7344be997921dec57959691e986763ee686888d5 - nvidia-xconfig-35.6.2/XF86Config-parser/Device.c
33211ca0a10f50e2c87b9e8feef6c1ab381b57a1 - nvidia-xconfig-35.6.2/XF86Config-parser/DRI.c
953b945f3b117d6fb44f1f738af17b6380a9ec72 - nvidia-xconfig-35.6.2/XF86Config-parser/Monitor.c
6c210ad0eaee1db3fec48ff01746cb054b4f9aaa - nvidia-xconfig-35.6.2/XF86Config-parser/Video.c
4407207cf890539dc604cff5b834c994b307729a - nvidia-xconfig-35.6.2/XF86Config-parser/Write.c
de1c758e29f217e1a99e4c076d54ac84bce98b18 - nvidia-xconfig-35.6.2/XF86Config-parser/Screen.c
c66a0a141e25e31b568fb9df41f17d7fb9e6d3b9 - nvidia-xconfig-35.6.2/XF86Config-parser/xf86Parser.h
9cbc29da282aa957f28b7fc83caf1e3b19ee2a52 - nvidia-xconfig-35.6.2/XF86Config-parser/Vendor.c
18711ff932af2202869a30f3b32d6d7fe7811c84 - nvidia-xconfig-35.6.2/XF86Config-parser/Layout.c
cda3a4ab05bf48ba28af35b5c4c632e968afc7fa - nvidia-xconfig-35.6.2/XF86Config-parser/Util.c
ec19d673a6a7d1d8f855f2d32d3e8f63046c3625 - nvidia-xconfig-35.6.2/XF86Config-parser/Files.c
ac878b26ded86a3c502a6a81fc4c4a96162afefb - nvidia-xconfig-35.6.2/XF86Config-parser/Merge.c
0a274c4bc54b6ae0f6d009e443bda0cb033d66b5 - nvidia-xconfig-35.6.2/XF86Config-parser/Pointer.c
3f2238c88d737bd329a9bca1ac4b0bcf77bb9ac2 - nvidia-xconfig-35.6.2/XF86Config-parser/xf86tokens.h
45ceb0129668346ae3e52d81bb6e2f97efadf9d0 - nvidia-xconfig-35.6.2/XF86Config-parser/Input.c
4d9b03ea3badceb6bdfdf6589e6731140ec44079 - nvidia-xconfig-35.6.2/XF86Config-parser/Generate.c
04efe162cf6d97882f2bb87f3712d9a65c2320f3 - nvidia-xconfig-35.6.2/XF86Config-parser/Scan.c
5d55b94375c2055cfa1578e4c7f34c90e63a33f7 - nvidia-xconfig-35.6.2/common-utils/gen-manpage-opts-helper.c
384e36102dcd08ed4c5de05b5e3b8a7cdb2e257d - nvidia-xconfig-35.6.2/common-utils/nvgetopt.c
dc2678d8a9d794a4b2b2718fce57ec087f21f54b - nvidia-xconfig-35.6.2/common-utils/common-utils.h
aac5cbf0e68e1da4e646c316a7c0e620304ee16b - nvidia-xconfig-35.6.2/common-utils/msg.c
e572cac43202f6c2af1c80b9e3901215126093ed - nvidia-xconfig-35.6.2/common-utils/nvgetopt.h
8a346196b052cfb1e06dd83d2ad1fe71e928d2b3 - nvidia-xconfig-35.6.2/common-utils/common-utils.c
1654638c567bc7f2bd70b54d807b498ab14c1061 - nvidia-xconfig-35.6.2/common-utils/nvpci-utils.h
8259a24058c714629f9819cc8c830ea9b202bb27 - nvidia-xconfig-35.6.2/common-utils/gen-manpage-opts-helper.h
524990f5497f9bbeb3d148b5e7dc8d2267c3163d - nvidia-xconfig-35.6.2/common-utils/nvpci-utils.c
abb5c1b445d9353f2d2840bda848cd16109710a4 - nvidia-xconfig-35.6.2/common-utils/msg.h

Change-Id: I99682b72c725a16fef77ba060c57fd78b05ae428
2025-07-01 06:51:17 -07:00

1355 lines
37 KiB
C

/*
* nvidia-xconfig: A tool for manipulating X config files,
* specifically for use by the NVIDIA Linux graphics driver.
*
* Copyright (C) 2005 NVIDIA Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses>.
*
*
* nvidia-xconfig.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <libgen.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "nvidia-xconfig.h"
#include "nvgetopt.h"
#include "msg.h"
#define TAB " "
#define BIGTAB " "
#define ORIG_SUFFIX ".nvidia-xconfig-original"
#define BACKUP_SUFFIX ".backup"
/*
* print_version() - print version information
*/
static void print_version(void)
{
nv_info_msg(NULL, "");
nv_info_msg(NULL, "%s", NV_ID_STRING);
nv_info_msg(TAB, "The NVIDIA X Configuration Tool.");
nv_info_msg(NULL, "");
nv_info_msg(TAB, "This program is used to manipulate X configuration files, "
"specifically to enable NVIDIA X driver functionality.");
nv_info_msg(NULL, "");
} /* print_version() */
static void print_summary(void)
{
nv_info_msg(NULL, "");
nv_info_msg(TAB, "In its normal operation, nvidia-xconfig finds the system "
"X configuration file (or generates a new X configuration "
"if it cannot find the system file), makes sure the "
"configuration is usable by the NVIDIA X driver, applies "
"any updates requested on the commandline, and writes the "
"new configuration to file.");
nv_info_msg(NULL, "");
nv_info_msg(TAB, "Please see the NVIDIA README for a description of NVIDIA "
"X configuration file options.");
nv_info_msg(NULL, "");
}
#include "option_table.h"
/*
* print_help() - loop through the __options[] table, and print the
* description of each option.
*/
static void print_help_helper(const char *name, const char *description)
{
nv_info_msg(TAB, "%s", name);
nv_info_msg(BIGTAB, "%s", description);
nv_info_msg(NULL, "");
}
static void print_help(int advanced)
{
unsigned int include_mask = 0;
print_version();
print_summary();
nv_info_msg(NULL, "");
nv_info_msg(NULL, "nvidia-xconfig [options]");
nv_info_msg(NULL, "");
if (!advanced) {
/* only print options with the ALWAYS flag */
include_mask |= NVGETOPT_HELP_ALWAYS;
}
nvgetopt_print_help(__options, include_mask, print_help_helper);
}
/*
* parse_commandline() - malloc an Options structure, initialize it,
* and fill in any pertinent data from the commandline arguments
*/
static void parse_commandline(Options *op, int argc, char *argv[])
{
int c, boolval;
char *strval;
int intval, disable;
double doubleval;
while (1) {
c = nvgetopt(argc, argv, __options, &strval,
&boolval, &intval, &doubleval, &disable);
if (c == -1)
break;
/* catch the boolean options */
if ((c >= XCONFIG_BOOL_OPTION_START) &&
(c <= (XCONFIG_BOOL_OPTION_START + XCONFIG_BOOL_OPTION_COUNT))) {
if (!check_boolean_option(op, c - XCONFIG_BOOL_OPTION_START, boolval)) {
goto fail;
}
set_boolean_option(op, c - XCONFIG_BOOL_OPTION_START, boolval);
continue;
}
switch (c) {
case 'v': print_version(); exit(0); break;
case 'c': op->xconfig = strval; break;
case 'o': op->output_xconfig = strval; break;
case 't': op->tree = TRUE; break;
case 'T': op->post_tree = TRUE; break;
case 'h': print_help(FALSE); exit(0); break;
case 'A': print_help(TRUE); exit(0); break;
case 's': nv_set_verbosity(NV_VERBOSITY_WARNING); break;
case 'a': op->enable_all_gpus = TRUE; break;
case '1': op->only_one_screen = TRUE; break;
case 'd': op->depth = intval;
if ((op->depth != 8) &&
(op->depth != 15) &&
(op->depth != 16) &&
(op->depth != 24) &&
(op->depth != 30)) {
fprintf(stderr, "\n");
fprintf(stderr, "Invalid depth: %d.\n", op->depth);
fprintf(stderr, "\n");
goto fail;
}
break;
case LAYOUT_OPTION: op->layout = strval; break;
case SCREEN_OPTION: op->screen = strval; break;
case DEVICE_OPTION: op->device = strval; break;
case BUSID_OPTION:
if (GET_BOOL_OPTION(op->boolean_option_values, ENABLE_PRIME_OPTION)) {
fprintf(stderr, "Unable to disable BUSID with PRIME enabled.\n");
goto fail;
}
op->busid = disable ? NV_DISABLE_STRING_OPTION : strval;
break;
case X_PREFIX_OPTION: op->gop.x_project_root = strval; break;
case KEYBOARD_OPTION: op->gop.keyboard = strval; break;
case KEYBOARD_LIST_OPTION: op->keyboard_list = TRUE; break;
case KEYBOARD_DRIVER_OPTION: op->gop.keyboard_driver = strval; break;
case MOUSE_OPTION: op->gop.mouse = strval; break;
case MOUSE_LIST_OPTION: op->mouse_list = TRUE; break;
case NVIDIA_CFG_PATH_OPTION: op->nvidia_cfg_path = strval; break;
case FORCE_GENERATE_OPTION: op->force_generate = TRUE; break;
case ACPID_SOCKET_PATH_OPTION:
if (disable) {
op->acpid_socket_path = NV_DISABLE_STRING_OPTION;
} else {
op->acpid_socket_path = strval;
}
break;
case HANDLE_SPECIAL_KEYS_OPTION:
{
const char *valid_values[] = {
"Always",
"Never",
"WhenNeeded",
NULL,
};
int i;
if (disable) {
op->handle_special_keys = NV_DISABLE_STRING_OPTION;
break;
}
for (i = 0; valid_values[i]; i++) {
if (!strcasecmp(strval, valid_values[i])) {
break;
}
}
if (valid_values[i]) {
op->handle_special_keys = strval;
} else {
fprintf(stderr, "Invalid HandleSpecialKeys option: %s.\n", strval);
goto fail;
}
break;
}
case TRANSPARENT_INDEX_OPTION:
/* mark as disabled, so we can remove the option later */
if (disable) {
op->transparent_index = -2;
break;
}
if (intval < 0 || intval > 255) {
fprintf(stderr, "\n");
fprintf(stderr, "Invalid transparent index: %d.\n", intval);
fprintf(stderr, "\n");
goto fail;
}
op->transparent_index = intval;
break;
case TV_STANDARD_OPTION:
{
const char* valid_values[] = {
"PAL-B",
"PAL-D",
"PAL-G",
"PAL-H",
"PAL-I",
"PAL-K1",
"PAL-M",
"PAL-N",
"PAL-NC",
"NTSC-J",
"NTSC-M",
"HD480i",
"HD480p",
"HD720p",
"HD1080i",
"HD1080p",
"HD576i",
"HD576p",
NULL
};
int i;
/* mark as disabled, so we can remove the option later */
if (disable) {
op->tv_standard = NV_DISABLE_STRING_OPTION;
break;
}
for (i = 0; valid_values[i]; i++) {
if (!strcasecmp(strval, valid_values[i]))
break;
}
if (valid_values[i]) {
op->tv_standard = strval;
} else {
fprintf(stderr, "Invalid TVStandard option: %s.\n", strval);
goto fail;
}
}
break;
case TV_OUT_FORMAT_OPTION:
/* mark as disabled, so we can remove the option later */
if (disable) {
op->tv_out_format = NV_DISABLE_STRING_OPTION;
break;
}
if (!strcasecmp(strval, "SVIDEO")) {
op->tv_out_format = "SVIDEO";
} else if (!strcasecmp(strval, "COMPOSITE")) {
op->tv_out_format = "COMPOSITE";
} else {
fprintf(stderr, "Invalid TVOutFormat option: %s.\n", strval);
goto fail;
}
break;
case COOL_BITS_OPTION:
/* mark as disabled, so we can remove the option later */
if (disable) {
op->cool_bits = -2;
break;
}
op->cool_bits = intval;
break;
case STEREO_OPTION:
/* mark as disabled, so we can remove the option later */
if (disable) {
op->stereo = -2;
break;
}
if (intval < 0 || intval > 14) {
fprintf(stderr, "\n");
fprintf(stderr, "Invalid stereo: %d.\n", intval);
fprintf(stderr, "\n");
goto fail;
}
op->stereo = intval;
break;
case MODE_OPTION:
if (boolval) {
/* add this mode */
nv_text_rows_append(&op->add_modes, strval);
} else {
/* remove this mode */
nv_text_rows_append(&op->remove_modes, strval);
}
break;
case MODE_LIST_OPTION:
{
char *token;
token = strtok(strval, " ");
if (!token) {
fprintf(stderr, "\n");
fprintf(stderr, "Invalid Mode List string: %s.\n", strval);
fprintf(stderr, "\n");
goto fail;
}
do {
nv_text_rows_append(&op->add_modes_list, token);
token = strtok(NULL, " ");
} while (token != NULL);
break;
}
case REMOVE_MODE_OPTION:
nv_text_rows_append(&op->remove_modes, strval);
break;
case META_MODES_OPTION:
op->metamodes_str = strval;
break;
case MULTI_GPU_OPTION: /* fall through */
case SLI_OPTION:
{
const char* valid_values[] = {
"0",
"no",
"off",
"false",
"single",
"mosaic",
NULL
};
if (disable) {
/* mark as disabled, so we can remove the option later */
strval = NV_DISABLE_STRING_OPTION;
} else {
/* check that the string is valid */
int i;
for (i = 0; valid_values[i]; i++) {
if (!strcasecmp(strval, valid_values[i]))
break;
}
if (!valid_values[i]) {
fprintf(stderr, "Invalid SLI option: %s.\n", strval);
goto fail;
}
}
if (c == MULTI_GPU_OPTION) {
op->multigpu = strval;
} else {
op->sli = strval;
}
}
break;
case PRESERVE_DRIVER_NAME_OPTION: op->preserve_driver = TRUE; break;
case DISABLE_SCF_OPTION: op->disable_scf = TRUE; break;
case QUERY_GPU_INFO_OPTION: op->query_gpu_info = TRUE; break;
case 'E':
op->extract_edids_from_file = strval;
break;
case EXTRACT_EDIDS_OUTPUT_FILE_OPTION:
op->extract_edids_output_file = strval;
break;
case NVIDIA_XINERAMA_INFO_ORDER_OPTION:
op->nvidia_xinerama_info_order =
disable ? NV_DISABLE_STRING_OPTION : strval;
break;
case METAMODE_ORIENTATION_OPTION:
{
const char* valid_values[] = {
"RightOf",
"LeftOf",
"Above",
"Below",
"Clone",
NULL
};
int i;
if (disable) {
op->metamode_orientation = NV_DISABLE_STRING_OPTION;
break;
}
for (i = 0; valid_values[i]; i++) {
if (!strcasecmp(strval, valid_values[i]))
break;
}
if (!valid_values[i]) {
fprintf(stderr, "Invalid MetaModeOrientation option: "
"\"%s\".\n", strval);
goto fail;
}
op->metamode_orientation = strval;
}
break;
case VIRTUAL_OPTION:
{
int ret, x, y;
if (disable) {
op->virtual.x = op->virtual.y = -1;
break;
}
ret = sscanf(strval, "%dx%d", &x, &y);
if (ret != 2) {
fprintf(stderr, "Invalid Virtual option: \"%s\".\n",
strval);
goto fail;
}
op->virtual.x = x;
op->virtual.y = y;
break;
}
case USE_DISPLAY_DEVICE_OPTION:
op->use_display_device =
disable ? NV_DISABLE_STRING_OPTION : strval;
break;
case CUSTOM_EDID_OPTION:
op->custom_edid = disable ? NV_DISABLE_STRING_OPTION : strval;
break;
case CONNECTED_MONITOR_OPTION:
op->connected_monitor =
disable ? NV_DISABLE_STRING_OPTION : strval;
break;
case REGISTRY_DWORDS_OPTION:
op->registry_dwords = disable ? NV_DISABLE_STRING_OPTION : strval;
break;
case COLOR_SPACE_OPTION:
op->color_space = disable ? NV_DISABLE_STRING_OPTION : strval;
break;
case COLOR_RANGE_OPTION:
op->color_range = disable ? NV_DISABLE_STRING_OPTION : strval;
break;
case FLATPANEL_PROPERTIES_OPTION:
op->flatpanel_properties =
disable ? NV_DISABLE_STRING_OPTION : strval;
break;
case NVIDIA_3DVISION_USB_PATH_OPTION:
op->nvidia_3dvision_usb_path = disable ? NV_DISABLE_STRING_OPTION : strval;
break;
case NVIDIA_3DVISIONPRO_CONFIG_FILE_OPTION:
op->nvidia_3dvisionpro_config_file = disable ? NV_DISABLE_STRING_OPTION : strval;
break;
case NVIDIA_3DVISION_DISPLAY_TYPE_OPTION:
/* mark as disabled, so we can remove the option later */
if (disable) {
op->nvidia_3dvision_display_type = -2;
break;
}
if (intval < 0 || intval > 2) {
fprintf(stderr, "\n");
fprintf(stderr, "Invalid 3D Vision display type option: %d.\n", intval);
fprintf(stderr, "\n");
goto fail;
}
op->nvidia_3dvision_display_type = intval;
break;
case RESTORE_ORIGINAL_BACKUP_OPTION:
op->restore_original_backup = TRUE;
break;
case NUM_X_SCREENS_OPTION:
if (intval < 1) {
fprintf(stderr, "\n");
fprintf(stderr, "Invalid number of X screens: %d.\n", intval);
fprintf(stderr, "\n");
goto fail;
}
/* Enable separate X screens */
set_boolean_option(op,
XCONFIG_BOOL_VAL(SEPARATE_X_SCREENS_BOOL_OPTION) -
XCONFIG_BOOL_OPTION_START, TRUE);
op->num_x_screens = intval;
break;
case FORCE_COMPOSITION_PIPELINE_OPTION:
op->force_composition_pipeline =
disable ? NV_DISABLE_STRING_OPTION : strval;
break;
case FORCE_FULL_COMPOSITION_PIPELINE_OPTION:
op->force_full_composition_pipeline =
disable ? NV_DISABLE_STRING_OPTION : strval;
break;
case ALLOW_HMD_OPTION:
op->allow_hmd = disable ? NV_DISABLE_STRING_OPTION : strval;
break;
default:
goto fail;
}
}
/* do tilde expansion on the filenames given */
op->xconfig = tilde_expansion(op->xconfig);
op->output_xconfig = tilde_expansion(op->output_xconfig);
return;
fail:
fprintf(stderr, "\n");
fprintf(stderr, "Invalid commandline, please run `%s --help` "
"for usage information.\n", argv[0]);
fprintf(stderr, "\n");
exit(1);
} /* parse_commandline() */
/*
* load_default_options - malloc an Options structure
* and initialize it with default values.
*
*/
static Options *load_default_options(void)
{
Options *op;
op = (Options *) nvalloc(sizeof(Options));
if (!op) return NULL;
op->depth = 24;
op->transparent_index = -1;
op->stereo = -1;
op->cool_bits = -1;
op->nvidia_3dvision_display_type = -1;
op->tv_over_scan = -1.0;
op->num_x_screens = -1;
xconfigGenerateLoadDefaultOptions(&op->gop);
/*
* XXX save the option structure so that printing routines can
* access it (and so that we don't have to carry the op everywhere
* just so that we can pass it to printing routines).
*/
{
extern Options *__op;
__op = op;
}
return op;
} /* load_default_options() */
/*
* backup_file() - create a backup of orig_filename, naming the backup
* file "<orig_filename>.<suffix>".
*
* XXX If we fail to write to the backup file (eg, it is in a
* read-only directory), then we should do something intelligent like
* write the backup to the user's home directory.
*/
static int backup_file(Options *op, const char *orig_filename,
const char *suffix)
{
char *filename;
int ret = FALSE;
/* construct the backup filename */
filename = nvstrcat(orig_filename, suffix, NULL);
/* if the backup file already exists, remove it */
if (access(filename, F_OK) == 0) {
if (unlink(filename) != 0) {
nv_error_msg("Unable to create backup file '%s' (%s)",
filename, strerror(errno));
goto done;
}
}
/* copy the file */
if (!copy_file(orig_filename, filename, 0644)) {
/* copy_file() prints out its own error messages */
goto done;
}
nv_info_msg(NULL, "Backed up file '%s' as '%s'", orig_filename, filename);
ret = TRUE;
done:
free(filename);
return ret;
} /* backup_file() */
/*
* find_xconfig() - search for an X config file.
*
* We search for the filename is this order:
*
* 1) "--output-xconfig" option
*
* 2) config->filename
*
* 3) use xf86openConfigFile()
*/
static char *find_xconfig(Options *op, XConfigPtr config)
{
char *filename = NULL;
/* 1) "--output-xconfig" option */
if (op->output_xconfig) {
filename = nvstrdup(op->output_xconfig);
}
/* config->filename */
if (!filename && config && config->filename) {
filename = nvstrdup(config->filename);
}
/* use xf86openConfigFile() */
if (!filename) {
const char *f;
f = xconfigOpenConfigFile(NULL, op->gop.x_project_root);
if (f) {
/* dup the string since closing the config file will free
the string */
filename = nvstrdup(f);
xconfigCloseConfigFile();
}
}
if (!filename) {
filename = nvstrdup("/etc/X11/xorg.conf");
}
return filename;
} /* find_xconfig() */
/*
* restore_backup - search for a backup file with the given suffix;
* if one is found, restore it.
*/
static int restore_backup(Options *op, XConfigPtr config, const char *suffix)
{
char *filename = find_xconfig(op, config);
char *backup = nvstrcat(filename, suffix, NULL);
struct stat st;
int ret = FALSE;
if (lstat(backup, &st) != 0) {
nv_error_msg("Unable to restore from original backup file '%s' (%s)",
backup, strerror(errno));
goto done;
}
/*
* do not restore files if the permissions might allow a malicious user to
* modify the backup, potentially tricking an administrator into restoring
* the modified backup.
*/
if (!S_ISREG(st.st_mode) /* non-regular files */ ||
st.st_uid != 0 /* not owned by root*/ ||
(st.st_gid != 0 && (st.st_mode & S_IWGRP)) /* non-root group write */ ||
(st.st_mode & S_IWOTH) /* world writable */ ) {
nv_error_msg("The permissions of the original backup file '%s' are too "
"loose to be trusted. The file will not be restored.", backup);
goto done;
}
/*
* if the backup is empty, assume that no original x config file existed
* and delete the current X config file.
*/
if (st.st_size == 0) {
if (unlink(filename) != 0) {
nv_error_msg("Unable to remove file '%s' (%s)",
filename, strerror(errno));
goto done;
}
} else {
/* copy the file */
if (!copy_file(backup, filename, 0644)) {
/* copy_file() prints out its own error messages */
goto done;
}
}
/* remove backup: a new one is created if nvidia-xconfig is run again */
if (access(backup, F_OK) == 0) {
if (unlink(backup) != 0) {
nv_error_msg("Unable to remove backup file '%s' (%s)",
backup, strerror(errno));
goto done;
}
}
if (st.st_size == 0) {
nv_info_msg(NULL, "The backup file '%s' was empty. This usually means "
"that nvidia-xconfig did not find an X configuration "
"file the first time it was run. The X configuration "
"file '%s' was deleted.",
backup, filename);
} else {
nv_info_msg(NULL, "Restored backup file '%s' to '%s'", backup, filename);
}
ret = TRUE;
done:
free(backup);
free(filename);
return ret;
} /* restore_backup() */
/*
* write_xconfig() - write the Xconfig to file.
*/
static int write_xconfig(Options *op, XConfigPtr config, int first_touch)
{
char *filename = find_xconfig(op, config);
char *d, *tmp = NULL;
int ret = FALSE;
/*
* XXX it's strange that lack of permission to write to the target
* location (the likely case with users not having write
* permission on /etc/X11/ will fail at backup time, rather than
* when we try to write the new file. Perhaps we should backup to
* a temporary location where we know we will have write access,
* try to do the write, and only if we succeed in the write, move
* the backup file into place.
*/
/* check that we can write to this location */
tmp = nvstrdup(filename);
d = dirname(tmp);
if (access(d, W_OK) != 0) {
nv_error_msg("Unable to write to directory '%s'.", d);
goto done;
}
/*
* if the file already exists, create a backup first. if this is our first
* time writing the x config, create a separate "original" backup file.
*/
if (access(filename, F_OK) == 0) {
if (first_touch && !backup_file(op, filename, ORIG_SUFFIX)) goto done;
if (!backup_file(op, filename, BACKUP_SUFFIX)) goto done;
}
/*
* if no file exists, and this is our first time writing the x config, back
* up an empty file to use as the "original" backup.
*/
else if (first_touch) {
char *fakeorig = nvstrcat(filename, ORIG_SUFFIX, NULL);
if (!copy_file("/dev/null", fakeorig, 0644)) {
nv_warning_msg("Unable to write an empty backup file \"%s\".",
fakeorig);
}
free(fakeorig);
}
/* write the config file */
if (!xconfigWriteConfigFile(filename, config)) {
nv_error_msg("Unable to write file \"%s\"; please use the "
"\"--output-xconfig\" commandline option to specify "
"an alternative output file.", filename);
goto done;
}
nv_info_msg(NULL, "New X configuration file written to '%s'", filename);
nv_info_msg(NULL, "");
/* Set the default depth in the Solaris Management Facility
* to the default depth of the first screen
*/
if (op->disable_scf == FALSE) {
if (!update_scf_depth(config->screens[0].defaultdepth)) {
goto done;
}
}
ret = TRUE;
done:
if (filename) free(filename);
if (tmp) free(tmp);
return ret;
} /* write_xconfig() */
/*
* find_banner_prefix() - helper for update_banner(); like
* 'strstr("# nvidia-xconfig:")' but allows arbitrary whitespace between
* '#' and 'n'.
*/
static char *find_banner_prefix(char *str)
{
char *s, *comment = NULL;
for (s = str; s && *s; s++) {
char c = *s;
/*
* if we aren't presently looking at a comment, and we found the
* start of a comment, then save it and goto the next char
*/
if ((!comment) && (c == '#')) {
comment = s;
continue;
}
if (comment) {
/* ignore space within the comment */
if (isspace(c)) {
continue;
}
/* if the prefix matches, then return the start of the comment */
if (strncmp(s, "nvidia-xconfig:", 15) == 0) {
return comment;
}
}
/* anything else forces us out of any current comment */
comment = NULL;
}
return NULL;
} /* find_banner_prefix() */
/*
* update_banner() - add our banner at the top of the config, but
* first we need to remove any lines that already include our prefix
* (because presumably they are a banner from an earlier run of
* nvidia-xconfig)
*/
static void update_banner(XConfigPtr config)
{
static const char *banner =
"X configuration file generated by nvidia-xconfig\n";
static const char *prefix =
"# nvidia-xconfig: ";
char *s = config->comment;
char *line, *eol, *tmp;
/* remove all lines that begin with the prefix */
while (s && (line = find_banner_prefix(s))) {
eol = strchr(line, '\n'); /* find the end of the line */
if (eol) {
eol++;
if (*eol == '\0') eol = NULL;
}
if (line == s) { /* the line with the prefix is at the start */
if (eol) { /* there is more after the prefix line */
tmp = strdup(eol);
free(s);
s = tmp;
} else { /* the prefix line is the only line */
free(s);
s = NULL;
}
} else { /* prefix line is in the middle or end */
*line = '\0';
tmp = nvstrcat(s, eol, NULL);
free(s);
s = tmp;
}
}
/* add our prefix lines at the start of the comment */
config->comment = nvstrcat(prefix, banner, "# " NV_ID_STRING "\n", s, NULL);
if (s) free(s);
} /* update_banner() */
/*
* find_system_xconfig() - find the system X config file and parse it;
* returns XConfigPtr if successful, otherwise returns NULL.
*/
static XConfigPtr find_system_xconfig(Options *op)
{
const char *filename;
XConfigPtr config;
XConfigError error;
/* Find and open the existing X config file */
filename = xconfigOpenConfigFile(op->xconfig, op->gop.x_project_root);
if (filename) {
nv_info_msg(NULL, "");
nv_info_msg(NULL, "Using X configuration file: \"%s\".", filename);
} else {
nv_warning_msg("Unable to locate/open X configuration file.");
return NULL;
}
/* Read the opened X config file */
error = xconfigReadConfigFile(&config);
if (error != XCONFIG_RETURN_SUCCESS) {
xconfigCloseConfigFile();
return NULL;;
}
/* Close the X config file */
xconfigCloseConfigFile();
/* Sanitize the X config file */
if (!xconfigSanitizeConfig(config, op->screen, &(op->gop))) {
xconfigFreeConfig(&config);
return NULL;
}
return config;
} /* find_system_xconfig() */
/*
* apply_enable_prime_settings() - if the ENABLE PRIME boolean option is
* enabled, add the required xconfig additions.
* returns a success/fail boolean.
*/
static int apply_enable_prime_settings(Options *op, XConfigPtr config,
XConfigLayoutPtr layout)
{
DevicesPtr pDevices;
if (GET_BOOL_OPTION(op->boolean_option_values, ENABLE_PRIME_OPTION)) {
/* Add an inactive device for the integrated graphics */
pDevices = find_devices(op);
if (!pDevices) {
nv_error_msg("Unable to find any GPUs in the system.");
return FALSE;
}
xconfigAddInactiveDevice(config, layout, pDevices->nDevices);
nv_info_msg(NULL, "X Configuration file set up for PRIME. Please run "
"\"xrandr --setprovideroutputsource modesetting "
"NVIDIA-0\" and \"xrandr --auto\" to enable. "
"See the README for more details.");
}
return TRUE;
} /* apply_enable_prime_settings() */
/*
* apply_enable_external_gpu_option() - if the ENABLE EXTERNAL GPU boolean
* option is enabled, add the AllowExternalGpus option to the ServerLayout
* section
* returns a success/fail boolean
*/
static int apply_enable_external_gpu_option(Options *op, XConfigPtr config,
XConfigLayoutPtr layout)
{
int egpu = GET_BOOL_OPTION(op->boolean_option_values,
ENABLE_EXTERNAL_GPU_BOOL_OPTION);
if (GET_BOOL_OPTION(op->boolean_options, ENABLE_EXTERNAL_GPU_BOOL_OPTION)) {
xconfigAddNewOption(&(layout->options),
"AllowExternalGpus",
(egpu ? "1" : "0"));
if (egpu) {
nv_info_msg(NULL, "X configuration file set up to allow detection "
"of External GPUs. If the eGPU does not work, "
"you may need to authorize the associated "
"Thunderbolt device.\n"
"Warning: System may become unstable if the "
"eGPU is hot-unplugged while X is running.\n"
"See \"Configuring External and Removable "
"GPUs\" in the README for more details.");
}
}
return TRUE;
} /* apply_enable_external_gpu_option */
static int update_xconfig(Options *op, XConfigPtr config)
{
XConfigLayoutPtr layout;
XConfigAdjacencyPtr adj;
int updated;
/* get the layout to update */
layout = get_layout(op, config);
if (!layout) {
return FALSE;
}
/* apply multi-display options */
if (!apply_multi_screen_options(op, config, layout)) {
return FALSE;
}
/* apply PRIME settings */
if (!apply_enable_prime_settings(op, config, layout)) {
return FALSE;
}
/* apply eGPU setting */
if (!apply_enable_external_gpu_option(op, config, layout)) {
return FALSE;
}
/*
* update the device and option for all screens, or the screen
* or device that was requested.
*/
updated = FALSE;
for (adj = layout->adjacencies; adj; adj = adj->next) {
if (!adj->screen) {
continue;
}
/* if screen option set: skip adj if not the requested screen */
if ((op->screen) &&
(xconfigNameCompare(op->screen, adj->screen->identifier) != 0)) {
continue;
}
/* if device option set: skip adj if not the requested device */
if ((op->device) &&
(xconfigNameCompare(op->device, adj->screen->device_name) != 0)) {
continue;
}
update_screen(op, config, adj->screen);
updated = TRUE;
}
if (op->screen && !updated) {
nv_error_msg("Unable to find screen '%s'", op->screen);
return FALSE;
}
if (op->device && !updated) {
nv_error_msg("Unable to find device '%s'", op->device);
return FALSE;
}
update_extensions(op, config);
update_modules(config);
update_server_flags(op, config);
update_banner(config);
return TRUE;
} /* update_xconfig() */
/*
* main program entry point
*
* The intended behavior is that, by default, nvidia-xconfig make the
* system's X config file usable by the NVIDIA X driver. If
* nvidia-xconfig cannot file the system's X config file, then it
* attempts to create one and make that usable.
*
*
*/
int main(int argc, char *argv[])
{
Options *op;
int ret;
XConfigPtr config = NULL;
int first_touch = 0;
/* Load defaults */
op = load_default_options();
if (!op) {
fprintf(stderr, "\nOut of memory error.\n\n");
return 1;
}
/* parse the commandline */
parse_commandline(op, argc, argv);
/*
* first, check for any of special options that cause us to exit
* early
*/
if (op->keyboard_list) {
nv_info_msg(NULL, "\nPossible keyboard types; the short name is what "
"should be passed to the \"--keyboard\" option.\n\n");
xconfigGeneratePrintPossibleKeyboards();
return 0;
}
if (op->mouse_list) {
nv_info_msg(NULL, "\nPossible mouse types; the short name is what should "
"be passed to the \"--mouse\" option.\n\n");
xconfigGeneratePrintPossibleMice();
return 0;
}
if (op->query_gpu_info) {
ret = query_gpu_info(op);
return (ret ? 0 : 1);
}
if (op->extract_edids_from_file) {
ret = extract_edids(op);
return (ret ? 0 : 1);
}
if (op->restore_original_backup) {
config = find_system_xconfig(op);
xconfigGetXServerInUse(&op->gop);
ret = restore_backup(op, config, ORIG_SUFFIX);
return (ret ? 0 : 1);
}
/*
* we want to open and parse the system's existing X config file,
* if possible
*/
if (!op->force_generate) {
config = find_system_xconfig(op);
}
/*
* pass the system config (if any) to the tree printer
*/
if (op->tree) {
ret = print_tree(op, config);
return (ret ? 0 : 1);
}
/*
* Get which X server is in use: Xorg or XFree86
*/
xconfigGetXServerInUse(&op->gop);
/*
* if we failed to find the system's config file, generate a new
* one
*/
if (!config) {
config = xconfigGenerate(&op->gop);
first_touch = 1;
}
/*
* if we don't have a valid config by now, something catestrophic
* happened
*/
if (!config) {
nv_error_msg("Unable to generate a usable X configuration file.");
return 1;
}
/* if a config file existed, check to see if it had an nvidia-xconfig
* banner: this would suggest that we've touched this file before.
*/
if (!first_touch) {
first_touch = (find_banner_prefix(config->comment) == NULL);
}
/* now, we have a good config; apply whatever the user requested */
update_xconfig(op, config);
/* print the config in tree format, if requested */
if (op->post_tree) {
ret = print_tree(op, config);
return (ret ? 0 : 1);
}
/* write the config back out to file */
if (!write_xconfig(op, config, first_touch)) {
return 1;
}
return 0;
} /* main() */