summaryrefslogtreecommitdiff
path: root/nvidia-xconfig.c
diff options
context:
space:
mode:
Diffstat (limited to 'nvidia-xconfig.c')
-rw-r--r--nvidia-xconfig.c277
1 files changed, 168 insertions, 109 deletions
diff --git a/nvidia-xconfig.c b/nvidia-xconfig.c
index 54934cc..afd4cdf 100644
--- a/nvidia-xconfig.c
+++ b/nvidia-xconfig.c
@@ -37,6 +37,8 @@
#define TAB " "
#define BIGTAB " "
+#define ORIG_SUFFIX ".nvidia-xconfig-original"
+#define BACKUP_SUFFIX ".backup"
/*
@@ -79,111 +81,35 @@ static void print_summary(void)
/*
- * cook_description() - the description string may contain text within
- * brackets, which is used by the manpage generator to denote text to
- * be italicized. We want to omit the bracket characters here.
- */
-
-static char *cook_description(const char *description)
-{
- int len;
- char *s, *dst;
- const char *src;
-
- len = strlen(description);
- s = nvalloc(len + 1);
-
- for (src = description, dst = s; *src; src++) {
- if (*src != '[' && (*src != ']')) {
- *dst = *src;
- dst++;
- }
- }
-
- *dst = '\0';
-
- return s;
-
-} /* cook_description() */
-
-
-/*
* 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)
+{
+ fmtoutp(TAB, name);
+ fmtoutp(BIGTAB, description);
+ fmtout("");
+}
+
static void print_help(int advanced)
{
- int i, j, len;
- char *msg, *tmp, scratch[8], arg[64];
- const NVGetoptOption *o;
-
+ unsigned int include_mask = 0;
+
print_version();
print_summary();
fmtout("");
fmtout("nvidia-xconfig [options]");
fmtout("");
-
- for (i = 0; __options[i].name; i++) {
- o = &__options[i];
-
- /*
- * if non-advanced help is requested, and the ALWAYS flag is
- * not set, then skip this option
- */
-
- if (!advanced && !(o->flags & NVGETOPT_HELP_ALWAYS)) continue;
-
- /* if we are going to need the argument, process it now */
-
- if (o->flags & NVGETOPT_HAS_ARGUMENT) {
- if (o->arg_name) {
- strcpy(arg, o->arg_name);
- } else {
- len = strlen(o->name);
- for (j = 0; j < len; j++) arg[j] = toupper(o->name[j]);
- arg[len] = '\0';
- }
- }
-
- msg = nvstrcat("--", o->name, NULL);
-
- if (isalpha(o->val)) {
- sprintf(scratch, "%c", o->val);
- if (o->flags & NVGETOPT_HAS_ARGUMENT) {
- tmp = nvstrcat("-", scratch, " ", arg, ", ", msg, NULL);
- } else {
- tmp = nvstrcat("-", scratch, ", ", msg, NULL);
- }
- free(msg);
- msg = tmp;
- }
-
- if (o->flags & NVGETOPT_HAS_ARGUMENT) {
- tmp = nvstrcat(msg, "=", arg, NULL);
- free(msg);
- msg = tmp;
- }
- if (((o->flags & NVGETOPT_IS_BOOLEAN) &&
- !(o->flags & NVGETOPT_HAS_ARGUMENT)) ||
- (o->flags & NVGETOPT_ALLOW_DISABLE)) {
- tmp = nvstrcat(msg, ", --no-", o->name, NULL);
- free(msg);
- msg = tmp;
- }
-
- fmtoutp(TAB, msg);
- if (o->description) {
- tmp = cook_description(o->description);
- fmtoutp(BIGTAB, tmp);
- free(tmp);
- }
- fmtout("");
- free(msg);
+ if (!advanced) {
+ /* only print options with the ALWAYS flag */
+ include_mask |= NVGETOPT_HELP_ALWAYS;
}
-} /* print_help() */
+
+ nvgetopt_print_help(__options, include_mask, print_help_helper);
+}
@@ -227,7 +153,7 @@ static void parse_commandline(Options *op, int argc, char *argv[])
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': op->silent = TRUE; break;
+ case 's': silence_fmt(1); break;
case 'a': op->enable_all_gpus = TRUE; break;
case '1': op->only_one_screen = TRUE; break;
@@ -751,6 +677,10 @@ static void parse_commandline(Options *op, int argc, char *argv[])
op->nvidia_3dvision_display_type = intval;
break;
+ case RESTORE_ORIGINAL_BACKUP_OPTION:
+ op->restore_original_backup = TRUE;
+ break;
+
default:
goto fail;
}
@@ -816,21 +746,22 @@ static Options *load_default_options(void)
/*
* backup_file() - create a backup of orig_filename, naming the backup
- * file "<original>.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)
+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, ".backup", NULL);
+ filename = nvstrcat(orig_filename, suffix, NULL);
/* if the backup file already exists, remove it */
@@ -849,7 +780,7 @@ static int backup_file(Options *op, const char *orig_filename)
goto done;
}
- fmtmsg("Backed up file '%s' as '%s'", orig_filename, filename);
+ fmtout("Backed up file '%s' as '%s'", orig_filename, filename);
ret = TRUE;
done:
@@ -863,7 +794,7 @@ static int backup_file(Options *op, const char *orig_filename)
/*
- * write_xconfig() - write the Xconfig to file.
+ * find_xconfig() - search for an X config file.
*
* We search for the filename is this order:
*
@@ -874,14 +805,12 @@ static int backup_file(Options *op, const char *orig_filename)
* 3) use xf86openConfigFile()
*
* 4) If the detected X server is XFree86, we use use "/etc/X11/XF86Config"
- * Otherwise we use "/etc/X11/xorg.conf",.
+ * Otherwise we use "/etc/X11/xorg.conf".
*/
-static int write_xconfig(Options *op, XConfigPtr config)
+static char *find_xconfig(Options *op, XConfigPtr config)
{
char *filename = NULL;
- char *d, *tmp = NULL;
- int ret = FALSE;
/* 1) "--output-xconfig" option */
@@ -891,7 +820,7 @@ static int write_xconfig(Options *op, XConfigPtr config)
/* config->filename */
- if (!filename && config->filename) {
+ if (!filename && config && config->filename) {
filename = nvstrdup(config->filename);
}
@@ -917,7 +846,103 @@ static int write_xconfig(Options *op, XConfigPtr config)
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) {
+ fmterr("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 */ ) {
+ fmterr("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) {
+ fmterr("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) {
+ fmterr("Unable to remove backup file '%s' (%s)",
+ backup, strerror(errno));
+ goto done;
+ }
+ }
+
+ if (st.st_size == 0) {
+ fmtout("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 {
+ fmtout("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
@@ -937,10 +962,27 @@ static int write_xconfig(Options *op, XConfigPtr config)
goto done;
}
- /* if the file already exists, create a backup first */
+ /*
+ * 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 (!backup_file(op, filename)) goto done;
+ 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)) {
+ fmtwarn("Unable to write an empty backup file \"%s\".", fakeorig);
+ }
+ free(fakeorig);
}
/* write the config file */
@@ -952,8 +994,8 @@ static int write_xconfig(Options *op, XConfigPtr config)
goto done;
}
- fmtmsg("New X configuration file written to '%s'", filename);
- fmtmsg("");
+ fmtout("New X configuration file written to '%s'", filename);
+ fmtout("");
/* Set the default depth in the Solaris Management Facility
@@ -1092,8 +1134,8 @@ static XConfigPtr find_system_xconfig(Options *op)
filename = xconfigOpenConfigFile(op->xconfig, op->gop.x_project_root);
if (filename) {
- fmtmsg("");
- fmtmsg("Using X configuration file: \"%s\".", filename);
+ fmtout("");
+ fmtout("Using X configuration file: \"%s\".", filename);
} else {
fmtwarn("Unable to locate/open X configuration file.");
return NULL;
@@ -1213,6 +1255,7 @@ int main(int argc, char *argv[])
Options *op;
int ret;
XConfigPtr config = NULL;
+ int first_touch = 0;
/* Load defaults */
@@ -1256,6 +1299,13 @@ int main(int argc, char *argv[])
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
@@ -1286,6 +1336,7 @@ int main(int argc, char *argv[])
if (!config) {
config = xconfigGenerate(&op->gop);
+ first_touch = 1;
}
/*
@@ -1298,6 +1349,14 @@ int main(int argc, char *argv[])
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);
@@ -1311,7 +1370,7 @@ int main(int argc, char *argv[])
/* write the config back out to file */
- if (!write_xconfig(op, config)) {
+ if (!write_xconfig(op, config, first_touch)) {
return 1;
}