From: drh Date: Wed, 23 Feb 2011 14:05:08 +0000 (+0000) Subject: Backport the os_unix.c error logging enhancements from X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c2e57196cb54af8208ee206167050f53419fd348;p=thirdparty%2Fsqlite.git Backport the os_unix.c error logging enhancements from check-in [01076528a43b61a]. FossilOrigin-Name: a4333b1545c6f96caef5b6dfaf94c8446e1b5d44 --- diff --git a/manifest b/manifest index d2291939a1..f7bcb79803 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,8 @@ -C Pull\sin\sthe\sfix\sto\sSTAT2\sprocessing\sfrom\scheck-in\n[70a3d81742f]. -D 2011-02-20T21:03:04.537 +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +C Backport\sthe\sos_unix.c\serror\slogging\senhancements\sfrom\ncheck-in\s[01076528a43b61a]. +D 2011-02-23T14:05:08.407 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 4547616ad2286053af6ccccefa242dc925e49bf0 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -160,7 +163,7 @@ F src/os.c 22ac61d06e72a0dac900400147333b07b13d8e1d F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9 F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f F src/os_os2.c 72d0b2e562952a2464308c4ce5f7913ac10bef3e -F src/os_unix.c 0240c5b547b4cf585c8cac351a95c3e85ce00772 +F src/os_unix.c c9f2a09124d78e2accd5738c78aabbccc07cb2f4 F src/os_win.c 2f90f7bdec714fad51cd31b4ecad3cc1b4bb5aad F src/pager.c 5b2210b4307c626a3b3ed7312161ec533958c094 F src/pager.h 0ea59db2a33bc6c2c02cae34de33367e1effdf76 @@ -575,6 +578,7 @@ F test/notify3.test d60923e186e0900f4812a845fcdfd8eea096e33a F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347 F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec +F test/oserror.test 5775264a41039856d211168713d916949227fedd F test/pager1.test e066fb2e2dc1ac1cd9ef2b44a28ae3cc79a9150f F test/pager2.test 0fbb6b6dc40ce1fecfe758c555a748ad2e9beaa3 F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f @@ -894,7 +898,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P e2616004dfaf61d776e448693971b6478552a635 -R d8e085383636be2d77c988420d503189 +P 692aafb17e7fca4e303ca14da2925cb95a22f71e +R 6770e6a4b417ada2ff6c98dd3dca2daa U drh -Z 0dcddd6d0b789a4a9ef8c5f0f596ab90 +Z 9c3c0b89eea505163f9778dd289c331f +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.6 (GNU/Linux) + +iD8DBQFNZRQXoxKgR168RlERAqTcAJ4i0CBz9MzbV5ibLtQ/BGYBaqlYuwCfXQoY +oux3l0HUdLba9EsW1zRLA/k= +=uIBr +-----END PGP SIGNATURE----- diff --git a/manifest.uuid b/manifest.uuid index defd04e6ec..989b74e812 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -692aafb17e7fca4e303ca14da2925cb95a22f71e \ No newline at end of file +a4333b1545c6f96caef5b6dfaf94c8446e1b5d44 \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index 72ac4c8048..102a2bffa6 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -736,6 +736,75 @@ struct unixInodeInfo { */ static unixInodeInfo *inodeList = 0; +/* +** +** This function - unixLogError_x(), is only ever called via the macro +** unixLogError(). +** +** It is invoked after an error occurs in an OS function and errno has been +** set. It logs a message using sqlite3_log() containing the current value of +** errno and, if possible, the human-readable equivalent from strerror() or +** strerror_r(). +** +** The first argument passed to the macro should be the error code that +** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). +** The two subsequent arguments should be the name of the OS function that +** failed (e.g. "unlink", "open") and the the associated file-system path, +** if any. +*/ +#define unixLogError(a,b,c) unixLogError_x(a,b,c,__LINE__) +static int unixLogError_x( + int errcode, /* SQLite error code */ + const char *zFunc, /* Name of OS function that failed */ + const char *zPath, /* File path associated with error */ + int iLine /* Source line number where error occurred */ +){ + char *zErr; /* Message from strerror() or equivalent */ + + /* If this is not a threadsafe build (SQLITE_THREADSAFE==0), then use + ** the strerror() function to obtain the human-readable error message + ** equivalent to errno. Otherwise, use strerror_r(). + */ +#if SQLITE_THREADSAFE && defined(HAVE_STRERROR_R) + char aErr[80]; + memset(aErr, 0, sizeof(aErr)); + zErr = aErr; + + /* If STRERROR_R_CHAR_P (set by autoconf scripts) or __USE_GNU is defined, + ** assume that the system provides the the GNU version of strerror_r() that + ** returns a pointer to a buffer containing the error message. That pointer + ** may point to aErr[], or it may point to some static storage somewhere. + ** Otherwise, assume that the system provides the POSIX version of + ** strerror_r(), which always writes an error message into aErr[]. + ** + ** If the code incorrectly assumes that it is the POSIX version that is + ** available, the error message will often be an empty string. Not a + ** huge problem. Incorrectly concluding that the GNU version is available + ** could lead to a segfault though. + */ +#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU) + zErr = +# endif + strerror_r(errno, aErr, sizeof(aErr)-1); + +#elif SQLITE_THREADSAFE + /* This is a threadsafe build, but strerror_r() is not available. */ + zErr = ""; +#else + /* Non-threadsafe build, use strerror(). */ + zErr = strerror(errno); +#endif + + assert( errcode!=SQLITE_OK ); + sqlite3_log(errcode, + "os_unix.c: %s() at line %d - \"%s\" errno=%d path=%s", + zFunc, iLine, zErr, errno, (zPath ? zPath : "n/a") + ); + + return errcode; +} + + /* ** Close all file descriptors accumuated in the unixInodeInfo->pUnused list. ** If all such file descriptors are closed without error, the list is @@ -755,7 +824,7 @@ static int closePendingFds(unixFile *pFile){ pNext = p->pNext; if( close(p->fd) ){ pFile->lastErrno = errno; - rc = SQLITE_IOERR_CLOSE; + rc = unixLogError(SQLITE_IOERR_CLOSE, "close", pFile->zPath); p->pNext = pError; pError = p; }else{ @@ -1408,7 +1477,7 @@ static int closeUnixFile(sqlite3_file *id){ int err = close(pFile->dirfd); if( err ){ pFile->lastErrno = errno; - return SQLITE_IOERR_DIR_CLOSE; + return unixLogError(SQLITE_IOERR_DIR_CLOSE, "close", pFile->zPath); }else{ pFile->dirfd=-1; } @@ -1417,7 +1486,7 @@ static int closeUnixFile(sqlite3_file *id){ int err = close(pFile->h); if( err ){ pFile->lastErrno = errno; - return SQLITE_IOERR_CLOSE; + return unixLogError(SQLITE_IOERR_CLOSE, "close", pFile->zPath); } } #if OS_VXWORKS @@ -2939,7 +3008,7 @@ static int unixSync(sqlite3_file *id, int flags){ SimulateIOError( rc=1 ); if( rc ){ pFile->lastErrno = errno; - return SQLITE_IOERR_FSYNC; + return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath); } if( pFile->dirfd>=0 ){ int err; @@ -2966,7 +3035,7 @@ static int unixSync(sqlite3_file *id, int flags){ pFile->dirfd = -1; }else{ pFile->lastErrno = errno; - rc = SQLITE_IOERR_DIR_CLOSE; + rc = unixLogError(SQLITE_IOERR_DIR_CLOSE, "close", pFile->zPath); } } return rc; @@ -2993,7 +3062,7 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){ rc = ftruncate(pFile->h, (off_t)nByte); if( rc ){ pFile->lastErrno = errno; - return SQLITE_IOERR_TRUNCATE; + return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath); }else{ #ifndef NDEBUG /* If we are doing a normal write to a database file (as opposed to @@ -3081,7 +3150,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ if( ftruncate(pFile->h, nSize) ){ pFile->lastErrno = errno; - return SQLITE_IOERR_TRUNCATE; + return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath); } iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1; do { @@ -3427,7 +3496,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ pShmNode->h = open(zShmFilename, O_RDWR|O_CREAT, (sStat.st_mode & 0777)); if( pShmNode->h<0 ){ - rc = SQLITE_CANTOPEN_BKPT; + rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename); goto shm_open_err; } @@ -3437,7 +3506,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ rc = SQLITE_OK; if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){ if( ftruncate(pShmNode->h, 0) ){ - rc = SQLITE_IOERR_SHMOPEN; + rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename); } } if( rc==SQLITE_OK ){ @@ -3543,7 +3612,7 @@ static int unixShmMap( */ if( !bExtend ) goto shmpage_out; if( ftruncate(pShmNode->h, nByte) ){ - rc = SQLITE_IOERR_SHMSIZE; + rc = unixLogError(SQLITE_IOERR_SHMSIZE,"ftruncate",pShmNode->zFilename); goto shmpage_out; } } @@ -4262,7 +4331,7 @@ static int openDirectory(const char *zFilename, int *pFd){ } } *pFd = fd; - return (fd>=0?SQLITE_OK:SQLITE_CANTOPEN_BKPT); + return (fd>=0?SQLITE_OK:unixLogError(SQLITE_CANTOPEN_BKPT, "open", zDirname)); } /* @@ -4603,7 +4672,7 @@ static int unixOpen( fd = open(zName, openFlags, openMode); } if( fd<0 ){ - rc = SQLITE_CANTOPEN_BKPT; + rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName); goto open_finished; } } @@ -4735,7 +4804,7 @@ static int unixDelete( UNUSED_PARAMETER(NotUsed); SimulateIOError(return SQLITE_IOERR_DELETE); if( unlink(zPath)==(-1) && errno!=ENOENT ){ - return SQLITE_IOERR_DELETE; + return unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath); } #ifndef SQLITE_DISABLE_DIRSYNC if( dirSync ){ @@ -4748,10 +4817,10 @@ static int unixDelete( if( fsync(fd) ) #endif { - rc = SQLITE_IOERR_DIR_FSYNC; + rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath); } if( close(fd)&&!rc ){ - rc = SQLITE_IOERR_DIR_CLOSE; + rc = unixLogError(SQLITE_IOERR_DIR_CLOSE, "close", zPath); } } } @@ -4835,7 +4904,7 @@ static int unixFullPathname( }else{ int nCwd; if( getcwd(zOut, nOut-1)==0 ){ - return SQLITE_CANTOPEN_BKPT; + return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath); } nCwd = (int)strlen(zOut); sqlite3_snprintf(nOut-nCwd, &zOut[nCwd], "/%s", zPath); diff --git a/test/oserror.test b/test/oserror.test new file mode 100644 index 0000000000..f2aa61008f --- /dev/null +++ b/test/oserror.test @@ -0,0 +1,112 @@ +# 2011 February 19 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing that error messages are logged via the +# sqlite3_log() mechanism when certain errors are encountered in the +# default unix or windows VFS modules. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +if {$::tcl_platform(platform)!="unix"} { finish_test ; return } +set ::testprefix oserror + +db close +sqlite3_shutdown +test_sqlite3_log xLog +proc xLog {error_code msg} { + if {[string match os_* $msg]} { + lappend ::log $msg + } +} + +proc do_re_test {tn script expression} { + uplevel do_test $tn [list [subst -nocommands { + set res [eval { $script }] + if {[regexp {$expression} [set res]]} { + set {} {$expression} + } else { + set res + } + }]] [list $expression] + +} + +#-------------------------------------------------------------------------- +# Tests oserror-1.* test failures in the open() system call. +# + +# Test a failure in open() due to too many files. +# +do_test 1.1.1 { + set ::log [list] + list [catch { + for {set i 0} {$i < 2000} {incr i} { sqlite3 dbh_$i test.db -readonly 1 } + } msg] $msg +} {1 {unable to open database file}} +do_test 1.1.2 { + catch { for {set i 0} {$i < 2000} {incr i} { dbh_$i close } } +} {1} + +do_re_test 1.1.3 { lindex $::log 0 } {^os_unix.c: open.*test.db$} + + +# Test a failure in open() due to the path being a directory. +# +do_test 1.2.1 { + file mkdir dir.db + set ::log [list] + list [catch { sqlite3 dbh dir.db } msg] $msg +} {1 {unable to open database file}} + +do_re_test 1.2.2 { lindex $::log 0 } {^os_unix.c: open.*dir.db$} + +# Test a failure in open() due to the path not existing. +# +do_test 1.3.1 { + set ::log [list] + list [catch { sqlite3 dbh /x/y/z/test.db } msg] $msg +} {1 {unable to open database file}} + +do_re_test 1.3.2 { lindex $::log 0 } {^os_unix.c: open.*test.db$} + +# Test a failure in open() due to the path not existing. +# +do_test 1.4.1 { + set ::log [list] + list [catch { sqlite3 dbh /root/test.db } msg] $msg +} {1 {unable to open database file}} + +do_re_test 1.4.2 { lindex $::log 0 } {^os_unix.c: open.*test.db$} + +#-------------------------------------------------------------------------- +# Tests oserror-1.* test failures in the unlink() system call. +# +do_test 2.1.1 { + set ::log [list] + file mkdir test.db-wal + forcedelete test.db + sqlite3 dbh test.db + catchsql { SELECT * FROM sqlite_master } dbh +} {1 {disk I/O error}} + +do_re_test 2.1.2 { lindex $::log 0 } {^os_unix.c: unlink.*test.db-wal$} +do_test 2.1.3 { + dbh close + forcedelete test.db-wal +} {} + + +sqlite3_shutdown +test_sqlite3_log +sqlite3_initialize +finish_test +