1 diff --git a/src/file.c b/src/file.c
2 index d1d1982..1655f6f 100644
5 @@ -125,6 +125,8 @@ int hcompar(const void *, const void *);
6 int loadscores(char *);
7 static int parseline(char *, char **, char **);
9 +void mkconfig(char *filename);
10 +void mkscore(char *filename);
11 static void readfile(char *, int);
12 static void setoptions(char *, char *, int);
14 @@ -1125,7 +1127,7 @@ void
18 - char userhigh[MAXPATHLEN], userconf[MAXPATHLEN];
19 + char userhigh[MAXPATHLEN], userconf[MAXPATHLEN], confdir[MAXPATHLEN];
22 if (xsnprintf(ruledir, sizeof(ruledir), "%s", RULEDIR)) {
23 @@ -1140,18 +1142,33 @@ readconfig(void)
24 readfile(CONFIGFILE, 1);
26 if ((envhome = getenv("HOME")) == NULL)
28 + xerr(1, "readconfig: environment variable HOME not set");
30 if (xsnprintf(userconf, sizeof(userconf), "%s/.typespeed/config",
34 + xerr(1, "readconfig: string error");
35 + if (xsnprintf(userhigh, sizeof(userhigh), "%s/.typespeed/score",
37 + xerr(1, "readconfig: string error");
39 if (stat(userconf, &sb) || (sb.st_mode & S_IFMT) != S_IFREG)
42 - if (xsnprintf(userhigh, sizeof(userhigh), "%s/.typespeed/score",
46 + if (xsnprintf(confdir, sizeof(confdir), "%s/.typespeed",
48 + xerr(1, "readconfig: string error");
49 + if(stat(confdir, &sb) == -1)
50 + if(mkdir(confdir, S_IRWXU | S_IRWXG | S_IRWXO))
51 + xerr(1, "readconfig: could not create config directory %s",
53 + /* create the user configuration with default values */
56 + /* check for the high score file */
57 + if (stat(userhigh, &sb) || (sb.st_mode & S_IFMT) != S_IFREG)
59 + /* create a blank high score file */
64 * Open a user writable high score.
65 @@ -1159,14 +1176,48 @@ readconfig(void)
66 * file. Protect system-wide high score file with group
67 * write permissions: privileged gid already dropped.
69 - if (close(hfd) == -1)
70 - xerr(1, "readconfig: close");
71 - if ((hfd = open(userhigh, O_RDWR, 0)) == -1)
72 + if ((hfd = open(userhigh, O_RDWR)) == -1)
73 xerr(1, "readconfig: open: %s", userhigh);
75 readfile(userconf, 1);
78 +#define DEFAULT_CONFIG "cheat = no\n" \
79 + "highorder = score cps tcps\n" \
80 + "ruledir = " RULEDIR "\n" \
81 + "worddir = " WORDDIR "\n"
84 + * Create the user configuration, with default values, at the given path.
87 +mkconfig(char *filename)
91 + if((cfd = open(filename, O_WRONLY | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO)) == -1)
92 + xerr(1, "mkconfig: open: %s", filename);
93 + if(write(cfd, DEFAULT_CONFIG, sizeof(DEFAULT_CONFIG)/sizeof(DEFAULT_CONFIG[0]) - 1) == -1)
94 + xerr(1, "mkconfig: write: %s", filename);
95 + if(close(cfd) == -1)
96 + xerr(1, "mkconfig: close: %s", filename);
100 + * Create the user high score file, which is just a blank file.
103 +mkscore(char *filename)
106 + if((sfd = open(filename, O_WRONLY | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO)) == -1)
107 + xerr(1, "mkscore: open: %s", filename);
108 + if(write(sfd, "", 0) == -1)
109 + xerr(1, "mkconfig: write: %s", filename);
110 + if(close(sfd) == -1)
111 + xerr(1, "mkconfig: close: %s", filename);
115 * Function used to open configuration and game rule files and to
116 * set options with function setoptions.
117 diff --git a/src/typespeed.c b/src/typespeed.c
118 index 7ac5ee2..77e9acb 100644
119 --- a/src/typespeed.c
120 +++ b/src/typespeed.c
121 @@ -319,8 +319,13 @@ main(int argc, char **argv)
124 /* just open high score file while being setgid games */
125 - if ((hfd = open(HIGHFILE, O_RDWR, 0)) == -1)
126 - xerr(1, "main: open: %s", HIGHFILE);
128 + * For NixOS, a global high score file doesn't make sense, so we just comment
129 + * this out. A high score file in the user's home directory will be opened
130 + * later in readconfig().
132 +/* if ((hfd = open(HIGHFILE, O_RDWR, 0)) == -1)
133 + xerr(1, "main: open: %s", HIGHFILE); */
136 /* drop privileges */
137 @@ -348,9 +353,9 @@ main(int argc, char **argv)
140 /* check file descriptors for consistency */
141 - if (hfd == STDIN_FILENO || hfd == STDOUT_FILENO ||
142 +/* if (hfd == STDIN_FILENO || hfd == STDOUT_FILENO ||
143 hfd == STDERR_FILENO)
146 if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO) ||
147 !isatty(STDERR_FILENO))
148 xerrx(1, "not fully connected to a terminal");