Bug 462534
| Summary: | SQL Config files should not be read more than once | ||||||
|---|---|---|---|---|---|---|---|
| Product: | Red Hat Enterprise Linux 5 | Reporter: | Bryan Mason <nobody+bjmason> | ||||
| Component: | mysql | Assignee: | Tom Lane <tgl> | ||||
| Status: | CLOSED ERRATA | QA Contact: | |||||
| Severity: | medium | Docs Contact: | |||||
| Priority: | medium | ||||||
| Version: | 5.2 | CC: | bmason, byte, hhorak, kvolny, patrickm, sghosh, tao | ||||
| Target Milestone: | rc | ||||||
| Target Release: | --- | ||||||
| Hardware: | All | ||||||
| OS: | Linux | ||||||
| Whiteboard: | |||||||
| Fixed In Version: | Doc Type: | Bug Fix | |||||
| Doc Text: | Story Points: | --- | |||||
| Clone Of: | Environment: | ||||||
| Last Closed: | 2009-09-02 09:45:54 UTC | Type: | --- | ||||
| Regression: | --- | Mount Type: | --- | ||||
| Documentation: | --- | CRM: | |||||
| Verified Versions: | Category: | --- | |||||
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |||||
| Cloudforms Team: | --- | Target Upstream Version: | |||||
| Embargoed: | |||||||
| Attachments: |
|
||||||
Created attachment 316912 [details]
Proposed patch
Adapted from upstream mysql-5.0.67
Hi Dave,
The backport was from the latest version of MySQL (version 5.0.67). The
change was made to init_default_directories(), which is called by
init_defaults(), which is called by a lot of different fiels within the
MySQL codebase. It's probably used by the various MySQL programs to load
the MySQL configuration files.
Since this was taken from a released version of MySQL, it presumably has
already undergone code review and some amount of testing by the upstream
MySQL community.
The root cause of the problem is that init_default_directories() loads the
default_directories array with the /etc directory twice. Once as "/etc/"
and then once as DEFAULT_SYSCONFDIR (which is #defined to "/etc"). After
init_default_directories() is called, default_directories looks like:
(gdb) print default_directories
$3 = {0x932f84 "/etc/", 0x8f8ea8 "", 0x932f95 "~/", 0x932f98 "/etc",
0x0,
0x0, 0x0, 0x0}
The main thing that the proposed patch does is to modify
init_default_directories() so that each directories are added by
add_directory(). add_directory() first calls normalize_dirname() to
change "/etc" into "/etc/", and then calls array_append_string_unique() to
add the directory onto the default_directories array only if the directory
doesn't already exist in the array. That way, /etc isn't added since
/etc/ is already in the array. With the new code, default_directories
looks like:
(gdb) print default_directories[0]
$1 = 0x10832a88 "/etc/"
(gdb) print default_directories[1]
$2 = 0x10832a90 ""
(gdb) print default_directories[2]
$3 = 0x10832a98 "~/"
(gdb) print default_directories[3]
$4 = 0x0
(gdb) print default_directories[4]
$5 = 0x0
(gdb) print default_directories[5]
$6 = 0x0
(gdb) print default_directories[6]
$7 = 0x0
(gdb) print default_directories[7]
$8 = 0x0
There may be an simpler way to work around this problem in RHEL. The bit
of code where /etc is double-entered into the default_directories array is
here (I've snipped all the bits of code that would be #ifdef'd out for
RHEL:
static void init_default_directories()
{
const char *env, **ptr= default_directories;
#ifdef __WIN__
[...]
#elif defined(__NETWARE__)
[...]
#else
#if defined(__EMX__) || defined(OS2)
[...]
#endif
[1] *ptr++= "/etc/";
#endif
if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV))))
*ptr++= env;
*ptr++= ""; /* Place for defaults_extra_file
*/
#if !defined(__WIN__) && !defined(__NETWARE__)
*ptr++= "~/";;
#elif defined(__WIN__)
[...]
#endif
#ifdef DEFAULT_SYSCONFDIR
if (DEFAULT_SYSCONFDIR != "")
[2] *ptr++= DEFAULT_SYSCONFDIR;
#endif
*ptr= 0; /* end marker */
}
If we were to comment out either the first bit of code[1] that adds
"/etc/" to the default_directories array or the bit of code[2] that adds
DEFAULT_SYSCONFDIR to the default_directories array, that would achieve
the same purpose with only a couple of changed lines -- much less
invasive, although more from upstream.
~ Bryan
This event sent from IssueTracker by dmaley
issue 218594
One other note. There's a _much_ simpler way to test that this issue has
been fixed. Running "/usr/libexec/mysqld --help --verbose" lists the
default directories. The version already in RHEL reports:
# rpm -q mysql-server
mysql-server-5.0.45-7.el5.x86_64
# /usr/libexec/mysqld --help --verbose | grep --after=1 '^Default
options'
Default options are read from the following files in the given order:
/etc/my.cnf ~/.my.cnf /etc/my.cnf
After applying the proposed patch, mysqld reports:
# rpm -q mysql-servermysql-server-5.0.45-7.it218594.5.el5.x86_64
# /usr/libexec/mysqld --help --verbose | grep --after=1 '^Default
options'
Default options are read from the following files in the given order:
/etc/my.cnf ~/.my.cnf
~ Bryan
This event sent from IssueTracker by dmaley
issue 218594
An advisory has been issued which should help the problem described in this bug report. This report is therefore being closed with a resolution of ERRATA. For more information on therefore solution and/or where to find the updated files, please follow the link below. You may reopen this bug report if the solution does not work for you. http://rhn.redhat.com/errata/RHSA-2009-1289.html |
Description of problem: Customer reports that his /etc/my.conf file is being read twice. Because of the double-loading /etc/my.cnf file, every time MySQL restarts the relay file changes and is not an actual file in the /var/run/mysqld directory, nor is it anywhere near numerical order. Here is the problem it causes - mysql> show slave statusG *************************** 1. row *************************** [...] Relay_Log_File: mysqld-relay-bin.000023 Relay_Log_Pos: 185588730 Relay_Master_Log_File: mysql-bin.000044 Slave_IO_Running: No Slave_SQL_Running: No Replicate_Do_DB: cdr,weboffice,cdr,weboffice Replicate_Ignore_DB: [...] 1 row in set (0.00 sec) and the /var/log/mysqld.log file shows repeated instances of: 080903 15:11:59 [ERROR] Could not find target log during relay log initialization 080903 15:11:59 [ERROR] Failed to initialize the master info structure Version-Release number of selected component (if applicable): mysql-5.0.45-7.el5 How reproducible: Every time Steps to Reproduce: 1. service mysqld start or 1. strace -o mysqld-strace.log /usr/libexec/mysqld --basedir=/usr \ --datadir=/var/lib/mysql --user=mysql \ --pid-file=/var/run/mysqld/mysqld.pid --skip-external-locking \ --socket=/var/lib/mysql/mysql.sock & Actual results: /etc/my.cnf is read twice, as evidenced by the following section of mysqld-strace.log: uname({sys="Linux", node="why-it218594.usersys.redhat.com", ...}) = 0 stat("/etc/my.cnf", {st_mode=S_IFREG|0644, st_size=310, ...}) = 0 open("/etc/my.cnf", O_RDONLY) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=310, ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b1bbde23000 read(3, "[mysqld]ndatadir=/var/lib/mysqln"..., 4096) = 310 read(3, "", 4096) = 0 close(3) = 0 munmap(0x2b1bbde23000, 4096) = 0 stat("/root/.my.cnf", 0x7fffecc9ba60) = -1 ENOENT (No such file or directory) stat("/etc/my.cnf", {st_mode=S_IFREG|0644, st_size=310, ...}) = 0 open("/etc/my.cnf", O_RDONLY) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=310, ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b1bbde23000 read(3, "[mysqld]ndatadir=/var/lib/mysqln"..., 4096) = 310 read(3, "", 4096) = 0 close(3) = 0 munmap(0x2b1bbde23000, 4096) = 0 lstat("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 getrlimit(RLIMIT_NOFILE, {rlim_cur=1024, rlim_max=1024}) = 0 Expected results: /etc/my.cnf should only be read once. Additional info: This bug is documented in http://bugs.mysql.com/bug.php?id=20748 "Bug#20748 SQL Config files should not be read more than once"