1 Last-Update: 2013-09-19
3 Index: xorg-server-1.14.2.901/configure.ac
4 ===================================================================
5 --- xorg-server-1.14.2.901.orig/configure.ac 2013-09-19 11:43:53.948797077 -0400
6 +++ xorg-server-1.14.2.901/configure.ac 2013-09-19 11:43:53.944797077 -0400
8 AC_ARG_WITH(xkb-path, AS_HELP_STRING([--with-xkb-path=PATH], [Path to XKB base dir (default: ${datadir}/X11/xkb)]),
9 [ XKBPATH="$withval" ],
10 [ XKBPATH="${datadir}/X11/xkb" ])
11 -AC_ARG_WITH(xkb-output, AS_HELP_STRING([--with-xkb-output=PATH], [Path to XKB output dir (default: ${datadir}/X11/xkb/compiled)]),
12 +AC_ARG_WITH(xkb-output, AS_HELP_STRING([--with-xkb-output=PATH], [Path to XKB output dir (default: ${localstatedir}/cache/xkb)]),
13 [ XKBOUTPUT="$withval" ],
14 - [ XKBOUTPUT="compiled" ])
15 + [ XKBOUTPUT="${localstatedir}/cache/xkb" ])
16 AC_ARG_WITH(default-xkb-rules, AS_HELP_STRING([--with-default-xkb-rules=RULES],
17 [Keyboard ruleset (default: base/evdev)]),
18 [ XKB_DFLT_RULES="$withval" ],
20 dnl Make sure XKM_OUTPUT_DIR is an absolute path
21 XKBOUTPUT_FIRSTCHAR=`echo $XKBOUTPUT | cut -b 1`
22 if [[ x$XKBOUTPUT_FIRSTCHAR != x/ -a x$XKBOUTPUT_FIRSTCHAR != 'x$' ]] ; then
23 - XKBOUTPUT="$XKB_BASE_DIRECTORY/$XKBOUTPUT"
24 + AC_MSG_ERROR([xkb-output must be an absolute path.])
27 dnl XKM_OUTPUT_DIR (used in code) must end in / or file names get hosed
28 Index: xorg-server-1.14.2.901/xkb/README.compiled
29 ===================================================================
30 --- xorg-server-1.14.2.901.orig/xkb/README.compiled 2013-09-19 11:43:53.948797077 -0400
31 +++ xorg-server-1.14.2.901/xkb/README.compiled 2013-09-19 11:43:53.944797077 -0400
33 or some other tool might destroy or replace the files in this directory,
34 so it is not a safe place to store compiled keymaps for long periods of
35 time. The default keymap for any server is usually stored in:
37 -where <num> is the display number of the server in question, which makes
38 -it possible for several servers *on the same host* to share the same
42 +where <SHA1> is the SHA1 hash of keymap source, so that compiled
43 +keymap of different keymap sources are stored in different files.
45 Unless the X server is modified, sharing this directory between servers on
46 different hosts could cause problems.
47 Index: xorg-server-1.14.2.901/xkb/ddxLoad.c
48 ===================================================================
49 --- xorg-server-1.14.2.901.orig/xkb/ddxLoad.c 2013-09-19 11:43:53.948797077 -0400
50 +++ xorg-server-1.14.2.901/xkb/ddxLoad.c 2013-09-19 11:51:04.744800715 -0400
53 #include <xkb-config.h>
55 +#ifdef HAVE_SHA1_IN_LIBGCRYPT /* Use libgcrypt for SHA1 */
57 +#else /* Use OpenSSL's libcrypto */
58 +#warning "xkbcomp caching support disabled"
65 #define XKBSRV_NEED_FILE_FUNCS
67 #include <X11/extensions/XI.h>
72 - * If XKM_OUTPUT_DIR specifies a path without a leading slash, it is
73 - * relative to the top-level XKB configuration directory.
74 - * Making the server write to a subdirectory of that directory
75 - * requires some work in the general case (install procedure
76 - * has to create links to /var or somesuch on many machines),
77 - * so we just compile into /usr/tmp for now.
79 -#ifndef XKM_OUTPUT_DIR
80 -#define XKM_OUTPUT_DIR "compiled/"
83 #define PRE_ERROR_MSG "\"The XKEYBOARD keymap compiler (xkbcomp) reports:\""
84 #define ERROR_PREFIX "\"> \""
85 #define POST_ERROR_MSG1 "\"Errors from xkbcomp are not fatal to the X server\""
90 -OutputDirectory(char *outdir, size_t size)
91 +OutputDirectory(char *outdir, size_t size, Bool *is_private_directory)
94 /* Can we write an xkm and then open it too? */
95 if (access(XKM_OUTPUT_DIR, W_OK | X_OK) == 0 &&
96 (strlen(XKM_OUTPUT_DIR) < size)) {
97 (void) strcpy(outdir, XKM_OUTPUT_DIR);
98 + if (is_private_directory)
99 + *is_private_directory = TRUE;
103 if (strlen(Win32TempDir()) + 1 < size) {
104 (void) strcpy(outdir, Win32TempDir());
105 (void) strcat(outdir, "\\");
106 + if (is_private_directory)
107 + *is_private_directory = FALSE;
111 if (strlen("/tmp/") < size) {
112 (void) strcpy(outdir, "/tmp/");
113 + if (is_private_directory)
114 + *is_private_directory = FALSE;
118 +#ifndef SHA_DIGEST_LENGTH
119 +#define SHA_DIGEST_LENGTH 20
123 +Sha1Asc(char sha1Asc[SHA_DIGEST_LENGTH * 2 + 1], const char *input)
126 + unsigned char sha1[SHA_DIGEST_LENGTH];
128 +#ifdef HAVE_SHA1_IN_LIBGCRYPT /* Use libgcrypt for SHA1 */
134 + if (!gcry_check_version(NULL))
136 + gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
137 + gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
141 + err = gcry_md_open(&h, GCRY_MD_SHA1, 0);
144 + gcry_md_write(h, input, strlen(input));
145 + memcpy(sha1, gcry_md_read(h, GCRY_MD_SHA1), 20);
149 + /* convert sha1 to sha1_asc */
150 + for (i = 0; i < SHA_DIGEST_LENGTH; ++i) {
151 + sprintf(sha1Asc + i * 2, "%02X", sha1[i]);
157 +/* call xkbcomp and compile XKB keymap, return xkm file name in
160 XkbDDXCompileKeymapByNames(XkbDescPtr xkb,
161 XkbComponentNamesPtr names,
163 - unsigned need, char *nameRtrn, int nameRtrnLen)
164 + unsigned need, char *nameRtrn, int nameRtrnLen,
165 + Bool *is_private_directory)
168 - char *buf = NULL, keymap[PATH_MAX], xkm_output_dir[PATH_MAX];
169 + char *buf = NULL, xkmfile[PATH_MAX], xkm_output_dir[PATH_MAX];
170 + char *tmpXkmFile = NULL;
171 + char *canonicalXkmFileName = NULL;
172 + char sha1Asc[SHA_DIGEST_LENGTH * 2 + 1], xkbKeyMapBuf[100 * 1024];
175 const char *emptystring = "";
176 char *xkbbasedirflag = NULL;
177 @@ -108,14 +155,68 @@
178 /* WIN32 has no popen. The input must be stored in a file which is
179 used as input for xkbcomp. xkbcomp does not read from stdin. */
180 char tmpname[PATH_MAX];
181 - const char *xkmfile = tmpname;
182 + const char *xkbfile = tmpname;
184 - const char *xkmfile = "-";
185 + const char *xkbfile = "-";
188 - snprintf(keymap, sizeof(keymap), "server-%s", display);
189 + /* Write keymap source (xkbfile) to memory buffer `xkbKeyMapBuf',
190 + of which SHA1 is generated and used as result xkm file name */
191 + memset(xkbKeyMapBuf, 0, sizeof(xkbKeyMapBuf));
192 + out = fmemopen(xkbKeyMapBuf, sizeof(xkbKeyMapBuf), "w");
194 + ErrorF("[xkb] Open xkbKeyMapBuf for writing failed\n");
197 + ret = XkbWriteXKBKeymapForNames(out, names, xkb, want, need);
198 + if (fclose(out) != 0) {
200 + ("[xkb] XkbWriteXKBKeymapForNames error, perhaps xkbKeyMapBuf is too small\n");
204 + if (xkbDebugFlags) {
205 + ErrorF("[xkb] XkbDDXCompileKeymapByNames compiling keymap:\n");
206 + fputs(xkbKeyMapBuf, stderr);
211 + ("[xkb] Generating XKB Keymap failed, giving up compiling keymap\n");
215 + DebugF("[xkb] computing SHA1 of keymap\n");
216 + if (Success == Sha1Asc(sha1Asc, xkbKeyMapBuf)) {
217 + snprintf(xkmfile, sizeof(xkmfile), "server-%s", sha1Asc);
220 + ErrorF("[xkb] Computing SHA1 of keymap failed, "
221 + "using display name instead as xkm file name\n");
222 + snprintf(xkmfile, sizeof(xkmfile), "server-%s", display);
225 + OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir), is_private_directory);
226 + /* set nameRtrn, fail if it's too small */
227 + if ((strlen(xkmfile) + 1 > nameRtrnLen) && nameRtrn) {
228 + ErrorF("[xkb] nameRtrn too small to hold xkmfile name\n");
231 + strncpy(nameRtrn, xkmfile, nameRtrnLen);
233 - OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir));
234 + /* if the xkm file already exists, reuse it */
235 + canonicalXkmFileName = Xprintf("%s%s.xkm", xkm_output_dir, xkmfile);
236 + if ((*is_private_directory) && (access(canonicalXkmFileName, R_OK) == 0)) {
237 + /* yes, we can reuse the old xkm file */
238 + LogMessage(X_INFO, "XKB: reuse xkmfile %s\n", canonicalXkmFileName);
242 + LogMessage(X_INFO, "XKB: generating xkmfile %s\n", canonicalXkmFileName);
244 + /* continue to call xkbcomp to compile the keymap. to avoid race
245 + condition, we compile it to a tmpfile then rename it to
249 strcpy(tmpname, Win32TempDir());
250 @@ -139,15 +240,21 @@
254 + if ((tmpXkmFile = tempnam(xkm_output_dir, NULL)) == NULL) {
255 + ErrorF("[xkb] Can't generate temp xkm file name");
261 "\"%s%sxkbcomp\" -w %d %s -xkm \"%s\" "
262 - "-em1 %s -emp %s -eml %s \"%s%s.xkm\"",
263 + "-em1 %s -emp %s -eml %s \"%s\"",
264 xkbbindir, xkbbindirsep,
265 ((xkbDebugFlags < 2) ? 1 :
266 ((xkbDebugFlags > 10) ? 10 : (int) xkbDebugFlags)),
267 - xkbbasedirflag ? xkbbasedirflag : "", xkmfile,
268 + xkbbasedirflag ? xkbbasedirflag : "", xkbfile,
269 PRE_ERROR_MSG, ERROR_PREFIX, POST_ERROR_MSG1,
270 - xkm_output_dir, keymap) == -1)
274 free(xkbbasedirflag);
279 + /* there's a potential race condition between calling tempnam()
280 + and invoking xkbcomp to write the result file (potential temp
281 + file name conflicts), but since xkbcomp is a standalone
282 + program, we have to live with this */
285 out = Popen(buf, "w");
287 @@ -165,32 +277,43 @@
292 - if (xkbDebugFlags) {
293 - ErrorF("[xkb] XkbDDXCompileKeymapByNames compiling keymap:\n");
294 - XkbWriteXKBKeymapForNames(stderr, names, xkb, want, need);
295 + /* write XKBKeyMapBuf to xkbcomp */
296 + if (EOF == fputs(xkbKeyMapBuf, out)) {
297 + ErrorF("[xkb] Sending keymap to xkbcomp failed\n");
302 - XkbWriteXKBKeymapForNames(out, names, xkb, want, need);
304 if (Pclose(out) == 0)
306 if (fclose(out) == 0 && System(buf) >= 0)
309 + /* xkbcomp success */
311 DebugF("[xkb] xkb executes: %s\n", buf);
313 - strlcpy(nameRtrn, keymap, nameRtrnLen);
315 + /* if canonicalXkmFileName already exists now, we simply
316 + overwrite it, this is OK */
317 + ret = rename(tmpXkmFile, canonicalXkmFileName);
319 + ErrorF("[xkb] Can't rename %s to %s, error: %s\n",
320 + tmpXkmFile, canonicalXkmFileName, strerror(errno));
322 + /* in case of error, don't unlink tmpXkmFile, leave i
337 - LogMessage(X_ERROR, "Error compiling keymap (%s)\n", keymap);
338 + LogMessage(X_ERROR, "Error compiling keymap (%s)\n", xkbfile);
340 /* remove the temporary file */
353 + if (canonicalXkmFileName)
354 + free(canonicalXkmFileName);
365 if (mapName != NULL) {
366 - OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir));
367 + OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir), NULL);
368 if ((XkbBaseDirectory != NULL) && (xkm_output_dir[0] != '/')
370 && (!isalpha(xkm_output_dir[0]) || xkm_output_dir[1] != ':')
373 char fileName[PATH_MAX];
375 + Bool is_private_directory;
378 if ((keybd == NULL) || (keybd->key == NULL) ||
382 else if (!XkbDDXCompileKeymapByNames(xkb, names, want, need,
383 - nameRtrn, nameRtrnLen)) {
384 + nameRtrn, nameRtrnLen,
385 + &is_private_directory)) {
386 LogMessage(X_ERROR, "XKB: Couldn't compile keymap\n");
390 (*xkbRtrn)->defined);
393 - (void) unlink(fileName);
394 + if (!is_private_directory)
395 + (void) unlink(fileName);
396 return (need | want) & (~missing);