Description:
Reported by a friend:
============================================
While trying to log into the server (without valid user information) I got:
Shutdown NOW!
shutdown: [pid 40292]
loggerinit[40289]: Can't connect to database server: 28000 Access denied for user 'grog'@'
localhost' (using password: NO) (1045)
It was repeatable (after rebooting), and I was able to confirm that it was really executing /sbin/shutdown, so I changed the permissions on that program, but still got a corresponding error message. Even after fixing the access permissions, it continued trying to shut down. Established it was happening in mysql_close, so set a breakpoint on fork and found:
Breakpoint 2, 0x28323bf4 in fork () from /lib/libc.so.6
(gdb) bt
#0 0x28323bf4 in fork () from /lib/libc.so.6
#1 0x282b01f5 in fork () from /usr/lib/libpthread.so.2
#2 0x282ece3f in system () from /lib/libc.so.6
#3 0x282ae346 in system () from /usr/lib/libpthread.so.2
#4 0x0804a20e in shutdown () at misc.c:357
#5 0x2823f388 in vio_close () from /usr/local/lib/mysql/libmysqlclient.so.15
#6 0x2823f02e in vio_delete () from /usr/local/lib/mysql/libmysqlclient.so.15
#7 0x2823a0cc in end_server () from /usr/local/lib/mysql/libmysqlclient.so.15
#8 0x2823b541 in mysql_close () from /usr/local/lib/mysql/libmysqlclient.so.15
#9 0x080498e8 in main (argc=1085, argv=0xbfbfe320, envp=0xbfbfe328) at loggerinit.c:289
(gdb)
That looks innocent enough. The code in vio_close is:
if (vio->type != VIO_CLOSED)
{
DBUG_ASSERT(vio->sd >= 0);
if (shutdown(vio->sd,2))
r= -1;
if (closesocket(vio->sd))
r= -1;
}
But shutdown is a system call that shuts down a socket; why is it invoking /sbin/shutdown to shut down the system? The clue is above: it's at line 357 of misc.c (the fact that it has a line number at all is a smoking gun). In our application we had:
void shutdown ()
{
/* shut unit down */
draw_menu_text (2, "Shutting Down");
sleep (3);
system ("/sbin/shutdown -p now");
}
So it's a name conflict. Changed the name to system_shutdown and all was well.
============================================
How to repeat:
2:13 ~/m/tmp/bug-greg$ head -1000 *.c Makefile
==> shutdown.c <==
#include <stdio.h>
void shutdown() {
fputs("*\n* shutdown() called\n*\n\n", stderr);
fflush(stderr);
}
==> t.c <==
#include <stdio.h>
#include <stdlib.h>
#include <mysql.h>
extern void shutdown();
void _die(const char *file, unsigned int line, MYSQL *dbh) {
fprintf(stderr, "ERROR: %s:%d: %s\n", file, line, dbh ? mysql_error(dbh) : "out of memory");
exit(EXIT_FAILURE);
}
#define die(dbh) _die(__FILE__, __LINE__, (dbh))
int main(void) {
MYSQL *dbh = mysql_init(NULL);
if (dbh == NULL)
die(dbh);
if (mysql_real_connect(dbh, NULL, "nonexistent_user", "broken_pass", NULL, 0, NULL, 0) == NULL)
die(dbh);
mysql_close(dbh);
exit(EXIT_SUCCESS);
}
==> Makefile <==
CPPFLAGS = -I/usr/local/include/mysql
CFLAGS = -g -O -W -Wall
LDFLAGS = -L/usr/local/lib/mysql
t: t.o shutdown.o
gcc -o $@ t.o shutdown.o $(LDFLAGS) -lmysqlclient -lz -lm
clean:
rm -f *.o *core* t
Suggested fix:
rename shutdown() in vio to a less common name