X-Git-Url: https://git.piment-noir.org/?p=deb_xorg-server.git;a=blobdiff_plain;f=debian%2Fpatches%2F190_cache-xkbcomp_output_for_fast_start_up.patch;fp=debian%2Fpatches%2F190_cache-xkbcomp_output_for_fast_start_up.patch;h=c5a08bce13b843b002cb4fe316dd45c812befdff;hp=0000000000000000000000000000000000000000;hb=7217e0ca50bba73dad94782e67980aeeb24ab693;hpb=a09e091a5c996d46a398abb27b06fe504591673f diff --git a/debian/patches/190_cache-xkbcomp_output_for_fast_start_up.patch b/debian/patches/190_cache-xkbcomp_output_for_fast_start_up.patch new file mode 100644 index 0000000..c5a08bc --- /dev/null +++ b/debian/patches/190_cache-xkbcomp_output_for_fast_start_up.patch @@ -0,0 +1,398 @@ +Last-Update: 2013-09-19 + +Index: xorg-server-1.14.2.901/configure.ac +=================================================================== +--- xorg-server-1.14.2.901.orig/configure.ac 2013-09-19 11:43:53.948797077 -0400 ++++ xorg-server-1.14.2.901/configure.ac 2013-09-19 11:43:53.944797077 -0400 +@@ -517,9 +517,9 @@ + AC_ARG_WITH(xkb-path, AS_HELP_STRING([--with-xkb-path=PATH], [Path to XKB base dir (default: ${datadir}/X11/xkb)]), + [ XKBPATH="$withval" ], + [ XKBPATH="${datadir}/X11/xkb" ]) +-AC_ARG_WITH(xkb-output, AS_HELP_STRING([--with-xkb-output=PATH], [Path to XKB output dir (default: ${datadir}/X11/xkb/compiled)]), ++AC_ARG_WITH(xkb-output, AS_HELP_STRING([--with-xkb-output=PATH], [Path to XKB output dir (default: ${localstatedir}/cache/xkb)]), + [ XKBOUTPUT="$withval" ], +- [ XKBOUTPUT="compiled" ]) ++ [ XKBOUTPUT="${localstatedir}/cache/xkb" ]) + AC_ARG_WITH(default-xkb-rules, AS_HELP_STRING([--with-default-xkb-rules=RULES], + [Keyboard ruleset (default: base/evdev)]), + [ XKB_DFLT_RULES="$withval" ], +@@ -1225,7 +1225,7 @@ + dnl Make sure XKM_OUTPUT_DIR is an absolute path + XKBOUTPUT_FIRSTCHAR=`echo $XKBOUTPUT | cut -b 1` + if [[ x$XKBOUTPUT_FIRSTCHAR != x/ -a x$XKBOUTPUT_FIRSTCHAR != 'x$' ]] ; then +- XKBOUTPUT="$XKB_BASE_DIRECTORY/$XKBOUTPUT" ++ AC_MSG_ERROR([xkb-output must be an absolute path.]) + fi + + dnl XKM_OUTPUT_DIR (used in code) must end in / or file names get hosed +Index: xorg-server-1.14.2.901/xkb/README.compiled +=================================================================== +--- xorg-server-1.14.2.901.orig/xkb/README.compiled 2013-09-19 11:43:53.948797077 -0400 ++++ xorg-server-1.14.2.901/xkb/README.compiled 2013-09-19 11:43:53.944797077 -0400 +@@ -4,10 +4,10 @@ + or some other tool might destroy or replace the files in this directory, + so it is not a safe place to store compiled keymaps for long periods of + time. The default keymap for any server is usually stored in: +- X-default.xkm +-where is the display number of the server in question, which makes +-it possible for several servers *on the same host* to share the same +-directory. ++ server-.xkm ++ ++where is the SHA1 hash of keymap source, so that compiled ++keymap of different keymap sources are stored in different files. + + Unless the X server is modified, sharing this directory between servers on + different hosts could cause problems. +Index: xorg-server-1.14.2.901/xkb/ddxLoad.c +=================================================================== +--- xorg-server-1.14.2.901.orig/xkb/ddxLoad.c 2013-09-19 11:43:53.948797077 -0400 ++++ xorg-server-1.14.2.901/xkb/ddxLoad.c 2013-09-19 11:51:04.744800715 -0400 +@@ -30,6 +30,12 @@ + + #include + ++#ifdef HAVE_SHA1_IN_LIBGCRYPT /* Use libgcrypt for SHA1 */ ++#include ++#else /* Use OpenSSL's libcrypto */ ++#warning "xkbcomp caching support disabled" ++#endif ++ + #include + #include + #include +@@ -43,20 +49,9 @@ + #define XKBSRV_NEED_FILE_FUNCS + #include + #include ++#include + #include "xkb.h" + +- /* +- * If XKM_OUTPUT_DIR specifies a path without a leading slash, it is +- * relative to the top-level XKB configuration directory. +- * Making the server write to a subdirectory of that directory +- * requires some work in the general case (install procedure +- * has to create links to /var or somesuch on many machines), +- * so we just compile into /usr/tmp for now. +- */ +-#ifndef XKM_OUTPUT_DIR +-#define XKM_OUTPUT_DIR "compiled/" +-#endif +- + #define PRE_ERROR_MSG "\"The XKEYBOARD keymap compiler (xkbcomp) reports:\"" + #define ERROR_PREFIX "\"> \"" + #define POST_ERROR_MSG1 "\"Errors from xkbcomp are not fatal to the X server\"" +@@ -69,35 +64,87 @@ + #endif + + static void +-OutputDirectory(char *outdir, size_t size) ++OutputDirectory(char *outdir, size_t size, Bool *is_private_directory) + { + #ifndef WIN32 + /* Can we write an xkm and then open it too? */ + if (access(XKM_OUTPUT_DIR, W_OK | X_OK) == 0 && + (strlen(XKM_OUTPUT_DIR) < size)) { + (void) strcpy(outdir, XKM_OUTPUT_DIR); ++ if (is_private_directory) ++ *is_private_directory = TRUE; + } + else + #else + if (strlen(Win32TempDir()) + 1 < size) { + (void) strcpy(outdir, Win32TempDir()); + (void) strcat(outdir, "\\"); ++ if (is_private_directory) ++ *is_private_directory = FALSE; + } + else + #endif + if (strlen("/tmp/") < size) { + (void) strcpy(outdir, "/tmp/"); ++ if (is_private_directory) ++ *is_private_directory = FALSE; + } + } + ++#ifndef SHA_DIGEST_LENGTH ++#define SHA_DIGEST_LENGTH 20 ++#endif ++ ++static Bool ++Sha1Asc(char sha1Asc[SHA_DIGEST_LENGTH * 2 + 1], const char *input) ++{ ++ int i; ++ unsigned char sha1[SHA_DIGEST_LENGTH]; ++ ++#ifdef HAVE_SHA1_IN_LIBGCRYPT /* Use libgcrypt for SHA1 */ ++ static int init; ++ gcry_md_hd_t h; ++ gcry_error_t err; ++ ++ if (!init) { ++ if (!gcry_check_version(NULL)) ++ return BadAlloc; ++ gcry_control(GCRYCTL_DISABLE_SECMEM, 0); ++ gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); ++ init = 1; ++ } ++ ++ err = gcry_md_open(&h, GCRY_MD_SHA1, 0); ++ if (err) ++ return BadAlloc; ++ gcry_md_write(h, input, strlen(input)); ++ memcpy(sha1, gcry_md_read(h, GCRY_MD_SHA1), 20); ++ gcry_md_close(h); ++#endif ++ ++ /* convert sha1 to sha1_asc */ ++ for (i = 0; i < SHA_DIGEST_LENGTH; ++i) { ++ sprintf(sha1Asc + i * 2, "%02X", sha1[i]); ++ } ++ ++ return Success; ++} ++ ++/* call xkbcomp and compile XKB keymap, return xkm file name in ++ nameRtrn */ + static Bool + XkbDDXCompileKeymapByNames(XkbDescPtr xkb, + XkbComponentNamesPtr names, + unsigned want, +- unsigned need, char *nameRtrn, int nameRtrnLen) ++ unsigned need, char *nameRtrn, int nameRtrnLen, ++ Bool *is_private_directory) + { + FILE *out; +- char *buf = NULL, keymap[PATH_MAX], xkm_output_dir[PATH_MAX]; ++ char *buf = NULL, xkmfile[PATH_MAX], xkm_output_dir[PATH_MAX]; ++ char *tmpXkmFile = NULL; ++ char *canonicalXkmFileName = NULL; ++ char sha1Asc[SHA_DIGEST_LENGTH * 2 + 1], xkbKeyMapBuf[100 * 1024]; ++ int ret, result; + + const char *emptystring = ""; + char *xkbbasedirflag = NULL; +@@ -108,14 +155,68 @@ + /* WIN32 has no popen. The input must be stored in a file which is + used as input for xkbcomp. xkbcomp does not read from stdin. */ + char tmpname[PATH_MAX]; +- const char *xkmfile = tmpname; ++ const char *xkbfile = tmpname; + #else +- const char *xkmfile = "-"; ++ const char *xkbfile = "-"; + #endif + +- snprintf(keymap, sizeof(keymap), "server-%s", display); ++ /* Write keymap source (xkbfile) to memory buffer `xkbKeyMapBuf', ++ of which SHA1 is generated and used as result xkm file name */ ++ memset(xkbKeyMapBuf, 0, sizeof(xkbKeyMapBuf)); ++ out = fmemopen(xkbKeyMapBuf, sizeof(xkbKeyMapBuf), "w"); ++ if (NULL == out) { ++ ErrorF("[xkb] Open xkbKeyMapBuf for writing failed\n"); ++ return FALSE; ++ } ++ ret = XkbWriteXKBKeymapForNames(out, names, xkb, want, need); ++ if (fclose(out) != 0) { ++ ErrorF ++ ("[xkb] XkbWriteXKBKeymapForNames error, perhaps xkbKeyMapBuf is too small\n"); ++ return FALSE; ++ } ++#ifdef DEBUG ++ if (xkbDebugFlags) { ++ ErrorF("[xkb] XkbDDXCompileKeymapByNames compiling keymap:\n"); ++ fputs(xkbKeyMapBuf, stderr); ++ } ++#endif ++ if (!ret) { ++ ErrorF ++ ("[xkb] Generating XKB Keymap failed, giving up compiling keymap\n"); ++ return FALSE; ++ } ++ ++ DebugF("[xkb] computing SHA1 of keymap\n"); ++ if (Success == Sha1Asc(sha1Asc, xkbKeyMapBuf)) { ++ snprintf(xkmfile, sizeof(xkmfile), "server-%s", sha1Asc); ++ } ++ else { ++ ErrorF("[xkb] Computing SHA1 of keymap failed, " ++ "using display name instead as xkm file name\n"); ++ snprintf(xkmfile, sizeof(xkmfile), "server-%s", display); ++ } ++ ++ OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir), is_private_directory); ++ /* set nameRtrn, fail if it's too small */ ++ if ((strlen(xkmfile) + 1 > nameRtrnLen) && nameRtrn) { ++ ErrorF("[xkb] nameRtrn too small to hold xkmfile name\n"); ++ return FALSE; ++ } ++ strncpy(nameRtrn, xkmfile, nameRtrnLen); + +- OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir)); ++ /* if the xkm file already exists, reuse it */ ++ canonicalXkmFileName = Xprintf("%s%s.xkm", xkm_output_dir, xkmfile); ++ if ((*is_private_directory) && (access(canonicalXkmFileName, R_OK) == 0)) { ++ /* yes, we can reuse the old xkm file */ ++ LogMessage(X_INFO, "XKB: reuse xkmfile %s\n", canonicalXkmFileName); ++ result = TRUE; ++ goto _ret; ++ } ++ LogMessage(X_INFO, "XKB: generating xkmfile %s\n", canonicalXkmFileName); ++ ++ /* continue to call xkbcomp to compile the keymap. to avoid race ++ condition, we compile it to a tmpfile then rename it to ++ xkmfile */ + + #ifdef WIN32 + strcpy(tmpname, Win32TempDir()); +@@ -139,15 +240,21 @@ + } + } + ++ if ((tmpXkmFile = tempnam(xkm_output_dir, NULL)) == NULL) { ++ ErrorF("[xkb] Can't generate temp xkm file name"); ++ result = FALSE; ++ goto _ret; ++ } ++ + if (asprintf(&buf, + "\"%s%sxkbcomp\" -w %d %s -xkm \"%s\" " +- "-em1 %s -emp %s -eml %s \"%s%s.xkm\"", ++ "-em1 %s -emp %s -eml %s \"%s\"", + xkbbindir, xkbbindirsep, + ((xkbDebugFlags < 2) ? 1 : + ((xkbDebugFlags > 10) ? 10 : (int) xkbDebugFlags)), +- xkbbasedirflag ? xkbbasedirflag : "", xkmfile, ++ xkbbasedirflag ? xkbbasedirflag : "", xkbfile, + PRE_ERROR_MSG, ERROR_PREFIX, POST_ERROR_MSG1, +- xkm_output_dir, keymap) == -1) ++ tmpXkmFile) == -1) + buf = NULL; + + free(xkbbasedirflag); +@@ -158,6 +265,11 @@ + return FALSE; + } + ++ /* there's a potential race condition between calling tempnam() ++ and invoking xkbcomp to write the result file (potential temp ++ file name conflicts), but since xkbcomp is a standalone ++ program, we have to live with this */ ++ + #ifndef WIN32 + out = Popen(buf, "w"); + #else +@@ -165,32 +277,43 @@ + #endif + + if (out != NULL) { +-#ifdef DEBUG +- if (xkbDebugFlags) { +- ErrorF("[xkb] XkbDDXCompileKeymapByNames compiling keymap:\n"); +- XkbWriteXKBKeymapForNames(stderr, names, xkb, want, need); ++ /* write XKBKeyMapBuf to xkbcomp */ ++ if (EOF == fputs(xkbKeyMapBuf, out)) { ++ ErrorF("[xkb] Sending keymap to xkbcomp failed\n"); ++ result = FALSE; ++ goto _ret; + } +-#endif +- XkbWriteXKBKeymapForNames(out, names, xkb, want, need); + #ifndef WIN32 + if (Pclose(out) == 0) + #else + if (fclose(out) == 0 && System(buf) >= 0) + #endif + { ++ /* xkbcomp success */ + if (xkbDebugFlags) + DebugF("[xkb] xkb executes: %s\n", buf); +- if (nameRtrn) { +- strlcpy(nameRtrn, keymap, nameRtrnLen); ++ ++ /* if canonicalXkmFileName already exists now, we simply ++ overwrite it, this is OK */ ++ ret = rename(tmpXkmFile, canonicalXkmFileName); ++ if (0 != ret) { ++ ErrorF("[xkb] Can't rename %s to %s, error: %s\n", ++ tmpXkmFile, canonicalXkmFileName, strerror(errno)); ++ ++ /* in case of error, don't unlink tmpXkmFile, leave i ++ for debugging */ ++ ++ result = FALSE; ++ goto _ret; + } +- free(buf); + #ifdef WIN32 + unlink(tmpname); + #endif +- return TRUE; ++ result = TRUE; ++ goto _ret; + } + else +- LogMessage(X_ERROR, "Error compiling keymap (%s)\n", keymap); ++ LogMessage(X_ERROR, "Error compiling keymap (%s)\n", xkbfile); + #ifdef WIN32 + /* remove the temporary file */ + unlink(tmpname); +@@ -205,8 +328,17 @@ + } + if (nameRtrn) + nameRtrn[0] = '\0'; +- free(buf); +- return FALSE; ++ result = FALSE; ++ ++ _ret: ++ if (tmpXkmFile) ++ free(tmpXkmFile); ++ if (canonicalXkmFileName) ++ free(canonicalXkmFileName); ++ if (buf) ++ free(buf); ++ ++ return result; + } + + static FILE * +@@ -217,7 +349,7 @@ + + buf[0] = '\0'; + if (mapName != NULL) { +- OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir)); ++ OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir), NULL); + if ((XkbBaseDirectory != NULL) && (xkm_output_dir[0] != '/') + #ifdef WIN32 + && (!isalpha(xkm_output_dir[0]) || xkm_output_dir[1] != ':') +@@ -256,6 +388,7 @@ + FILE *file; + char fileName[PATH_MAX]; + unsigned missing; ++ Bool is_private_directory; + + *xkbRtrn = NULL; + if ((keybd == NULL) || (keybd->key == NULL) || +@@ -271,7 +404,8 @@ + return 0; + } + else if (!XkbDDXCompileKeymapByNames(xkb, names, want, need, +- nameRtrn, nameRtrnLen)) { ++ nameRtrn, nameRtrnLen, ++ &is_private_directory)) { + LogMessage(X_ERROR, "XKB: Couldn't compile keymap\n"); + return 0; + } +@@ -293,7 +427,8 @@ + (*xkbRtrn)->defined); + } + fclose(file); +- (void) unlink(fileName); ++ if (!is_private_directory) ++ (void) unlink(fileName); + return (need | want) & (~missing); + } +