Annotation of embedaddon/sqlite3/src/test_syscall.c, revision 1.1.1.1

1.1       misho       1: /*
                      2: ** 2011 March 28
                      3: **
                      4: ** The author disclaims copyright to this source code.  In place of
                      5: ** a legal notice, here is a blessing:
                      6: **
                      7: **    May you do good and not evil.
                      8: **    May you find forgiveness for yourself and forgive others.
                      9: **    May you share freely, never taking more than you give.
                     10: **
                     11: *************************************************************************
                     12: **
                     13: ** The code in this file implements a Tcl interface used to test error
                     14: ** handling in the os_unix.c module. Wrapper functions that support fault
                     15: ** injection are registered as the low-level OS functions using the 
                     16: ** xSetSystemCall() method of the VFS. The Tcl interface is as follows:
                     17: **
                     18: **
                     19: **   test_syscall install LIST
                     20: **     Install wrapper functions for all system calls in argument LIST.
                     21: **     LIST must be a list consisting of zero or more of the following
                     22: **     literal values:
                     23: **
                     24: **         open        close      access   getcwd   stat      fstat    
                     25: **         ftruncate   fcntl      read     pread    pread64   write
                     26: **         pwrite      pwrite64   fchmod   fallocate
                     27: **
                     28: **   test_syscall uninstall
                     29: **     Uninstall all wrapper functions.
                     30: **
                     31: **   test_syscall fault ?COUNT PERSIST?
                     32: **     If [test_syscall fault] is invoked without the two arguments, fault
                     33: **     injection is disabled. Otherwise, fault injection is configured to
                     34: **     cause a failure on the COUNT'th next call to a system call with a
                     35: **     wrapper function installed. A COUNT value of 1 means fail the next
                     36: **     system call. 
                     37: ** 
                     38: **     Argument PERSIST is interpreted as a boolean. If true, the all
                     39: **     system calls following the initial failure also fail. Otherwise, only
                     40: **     the single transient failure is injected.
                     41: **
                     42: **   test_syscall errno CALL ERRNO
                     43: **     Set the value that the global "errno" is set to following a fault
                     44: **     in call CALL. Argument CALL must be one of the system call names
                     45: **     listed above (under [test_syscall install]). ERRNO is a symbolic
                     46: **     name (i.e. "EACCES"). Not all errno codes are supported. Add extra
                     47: **     to the aErrno table in function test_syscall_errno() below as 
                     48: **     required.
                     49: **
                     50: **   test_syscall reset ?SYSTEM-CALL?
                     51: **     With no argument, this is an alias for the [uninstall] command. However,
                     52: **     this command uses a VFS call of the form:
                     53: **
                     54: **       xSetSystemCall(pVfs, 0, 0);
                     55: **
                     56: **     To restore the default system calls. The [uninstall] command restores
                     57: **     each system call individually by calling (i.e.):
                     58: **
                     59: **       xSetSystemCall(pVfs, "open", 0);
                     60: **
                     61: **     With an argument, this command attempts to reset the system call named
                     62: **     by the parameter using the same method as [uninstall].
                     63: **
                     64: **   test_syscall exists SYSTEM-CALL
                     65: **     Return true if the named system call exists. Or false otherwise.
                     66: **
                     67: **   test_syscall list
                     68: **     Return a list of all system calls. The list is constructed using
                     69: **     the xNextSystemCall() VFS method.
                     70: */
                     71: 
                     72: #include "sqlite3.h"
                     73: #include "tcl.h"
                     74: #include <stdlib.h>
                     75: #include <string.h>
                     76: #include <assert.h>
                     77: 
                     78: #include "sqliteInt.h"
                     79: #if SQLITE_OS_UNIX
                     80: 
                     81: /* From test1.c */
                     82: extern const char *sqlite3TestErrorName(int);
                     83: 
                     84: #include <sys/types.h>
                     85: #include <errno.h>
                     86: 
                     87: static struct TestSyscallGlobal {
                     88:   int bPersist;                   /* 1 for persistent errors, 0 for transient */
                     89:   int nCount;                     /* Fail after this many more calls */
                     90:   int nFail;                      /* Number of failures that have occurred */
                     91: } gSyscall = { 0, 0 };
                     92: 
                     93: static int ts_open(const char *, int, int);
                     94: static int ts_close(int fd);
                     95: static int ts_access(const char *zPath, int mode);
                     96: static char *ts_getcwd(char *zPath, size_t nPath);
                     97: static int ts_stat(const char *zPath, struct stat *p);
                     98: static int ts_fstat(int fd, struct stat *p);
                     99: static int ts_ftruncate(int fd, off_t n);
                    100: static int ts_fcntl(int fd, int cmd, ... );
                    101: static int ts_read(int fd, void *aBuf, size_t nBuf);
                    102: static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off);
                    103: static int ts_pread64(int fd, void *aBuf, size_t nBuf, off_t off);
                    104: static int ts_write(int fd, const void *aBuf, size_t nBuf);
                    105: static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off);
                    106: static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, off_t off);
                    107: static int ts_fchmod(int fd, mode_t mode);
                    108: static int ts_fallocate(int fd, off_t off, off_t len);
                    109: 
                    110: 
                    111: struct TestSyscallArray {
                    112:   const char *zName;
                    113:   sqlite3_syscall_ptr xTest;
                    114:   sqlite3_syscall_ptr xOrig;
                    115:   int default_errno;              /* Default value for errno following errors */
                    116:   int custom_errno;               /* Current value for errno if error */
                    117: } aSyscall[] = {
                    118:   /*  0 */ { "open",      (sqlite3_syscall_ptr)ts_open,      0, EACCES, 0 },
                    119:   /*  1 */ { "close",     (sqlite3_syscall_ptr)ts_close,     0, 0, 0 },
                    120:   /*  2 */ { "access",    (sqlite3_syscall_ptr)ts_access,    0, 0, 0 },
                    121:   /*  3 */ { "getcwd",    (sqlite3_syscall_ptr)ts_getcwd,    0, 0, 0 },
                    122:   /*  4 */ { "stat",      (sqlite3_syscall_ptr)ts_stat,      0, 0, 0 },
                    123:   /*  5 */ { "fstat",     (sqlite3_syscall_ptr)ts_fstat,     0, 0, 0 },
                    124:   /*  6 */ { "ftruncate", (sqlite3_syscall_ptr)ts_ftruncate, 0, EIO, 0 },
                    125:   /*  7 */ { "fcntl",     (sqlite3_syscall_ptr)ts_fcntl,     0, EACCES, 0 },
                    126:   /*  8 */ { "read",      (sqlite3_syscall_ptr)ts_read,      0, 0, 0 },
                    127:   /*  9 */ { "pread",     (sqlite3_syscall_ptr)ts_pread,     0, 0, 0 },
                    128:   /* 10 */ { "pread64",   (sqlite3_syscall_ptr)ts_pread64,   0, 0, 0 },
                    129:   /* 11 */ { "write",     (sqlite3_syscall_ptr)ts_write,     0, 0, 0 },
                    130:   /* 12 */ { "pwrite",    (sqlite3_syscall_ptr)ts_pwrite,    0, 0, 0 },
                    131:   /* 13 */ { "pwrite64",  (sqlite3_syscall_ptr)ts_pwrite64,  0, 0, 0 },
                    132:   /* 14 */ { "fchmod",    (sqlite3_syscall_ptr)ts_fchmod,    0, 0, 0 },
                    133:   /* 15 */ { "fallocate", (sqlite3_syscall_ptr)ts_fallocate, 0, 0, 0 },
                    134:            { 0, 0, 0, 0, 0 }
                    135: };
                    136: 
                    137: #define orig_open      ((int(*)(const char *, int, int))aSyscall[0].xOrig)
                    138: #define orig_close     ((int(*)(int))aSyscall[1].xOrig)
                    139: #define orig_access    ((int(*)(const char*,int))aSyscall[2].xOrig)
                    140: #define orig_getcwd    ((char*(*)(char*,size_t))aSyscall[3].xOrig)
                    141: #define orig_stat      ((int(*)(const char*,struct stat*))aSyscall[4].xOrig)
                    142: #define orig_fstat     ((int(*)(int,struct stat*))aSyscall[5].xOrig)
                    143: #define orig_ftruncate ((int(*)(int,off_t))aSyscall[6].xOrig)
                    144: #define orig_fcntl     ((int(*)(int,int,...))aSyscall[7].xOrig)
                    145: #define orig_read      ((ssize_t(*)(int,void*,size_t))aSyscall[8].xOrig)
                    146: #define orig_pread     ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].xOrig)
                    147: #define orig_pread64   ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].xOrig)
                    148: #define orig_write     ((ssize_t(*)(int,const void*,size_t))aSyscall[11].xOrig)
                    149: #define orig_pwrite    ((ssize_t(*)(int,const void*,size_t,off_t))\
                    150:                        aSyscall[12].xOrig)
                    151: #define orig_pwrite64  ((ssize_t(*)(int,const void*,size_t,off_t))\
                    152:                        aSyscall[13].xOrig)
                    153: #define orig_fchmod    ((int(*)(int,mode_t))aSyscall[14].xOrig)
                    154: #define orig_fallocate ((int(*)(int,off_t,off_t))aSyscall[15].xOrig)
                    155: 
                    156: /*
                    157: ** This function is called exactly once from within each invocation of a
                    158: ** system call wrapper in this file. It returns 1 if the function should
                    159: ** fail, or 0 if it should succeed.
                    160: */
                    161: static int tsIsFail(void){
                    162:   gSyscall.nCount--;
                    163:   if( gSyscall.nCount==0 || (gSyscall.nFail && gSyscall.bPersist) ){
                    164:     gSyscall.nFail++;
                    165:     return 1;
                    166:   }
                    167:   return 0;
                    168: }
                    169: 
                    170: /*
                    171: ** Return the current error-number value for function zFunc. zFunc must be
                    172: ** the name of a system call in the aSyscall[] table.
                    173: **
                    174: ** Usually, the current error-number is the value that errno should be set
                    175: ** to if the named system call fails. The exception is "fallocate". See 
                    176: ** comments above the implementation of ts_fallocate() for details.
                    177: */
                    178: static int tsErrno(const char *zFunc){
                    179:   int i;
                    180:   int nFunc = strlen(zFunc);
                    181:   for(i=0; aSyscall[i].zName; i++){
                    182:     if( strlen(aSyscall[i].zName)!=nFunc ) continue;
                    183:     if( memcmp(aSyscall[i].zName, zFunc, nFunc) ) continue;
                    184:     return aSyscall[i].custom_errno;
                    185:   }
                    186: 
                    187:   assert(0);
                    188:   return 0;
                    189: }
                    190: 
                    191: /*
                    192: ** A wrapper around tsIsFail(). If tsIsFail() returns non-zero, set the
                    193: ** value of errno before returning.
                    194: */ 
                    195: static int tsIsFailErrno(const char *zFunc){
                    196:   if( tsIsFail() ){
                    197:     errno = tsErrno(zFunc);
                    198:     return 1;
                    199:   }
                    200:   return 0;
                    201: }
                    202: 
                    203: /*
                    204: ** A wrapper around open().
                    205: */
                    206: static int ts_open(const char *zFile, int flags, int mode){
                    207:   if( tsIsFailErrno("open") ){
                    208:     return -1;
                    209:   }
                    210:   return orig_open(zFile, flags, mode);
                    211: }
                    212: 
                    213: /*
                    214: ** A wrapper around close().
                    215: */
                    216: static int ts_close(int fd){
                    217:   if( tsIsFail() ){
                    218:     /* Even if simulating an error, close the original file-descriptor. 
                    219:     ** This is to stop the test process from running out of file-descriptors
                    220:     ** when running a long test. If a call to close() appears to fail, SQLite
                    221:     ** never attempts to use the file-descriptor afterwards (or even to close
                    222:     ** it a second time).  */
                    223:     orig_close(fd);
                    224:     return -1;
                    225:   }
                    226:   return orig_close(fd);
                    227: }
                    228: 
                    229: /*
                    230: ** A wrapper around access().
                    231: */
                    232: static int ts_access(const char *zPath, int mode){
                    233:   if( tsIsFail() ){
                    234:     return -1;
                    235:   }
                    236:   return orig_access(zPath, mode);
                    237: }
                    238: 
                    239: /*
                    240: ** A wrapper around getcwd().
                    241: */
                    242: static char *ts_getcwd(char *zPath, size_t nPath){
                    243:   if( tsIsFail() ){
                    244:     return NULL;
                    245:   }
                    246:   return orig_getcwd(zPath, nPath);
                    247: }
                    248: 
                    249: /*
                    250: ** A wrapper around stat().
                    251: */
                    252: static int ts_stat(const char *zPath, struct stat *p){
                    253:   if( tsIsFail() ){
                    254:     return -1;
                    255:   }
                    256:   return orig_stat(zPath, p);
                    257: }
                    258: 
                    259: /*
                    260: ** A wrapper around fstat().
                    261: */
                    262: static int ts_fstat(int fd, struct stat *p){
                    263:   if( tsIsFailErrno("fstat") ){
                    264:     return -1;
                    265:   }
                    266:   return orig_fstat(fd, p);
                    267: }
                    268: 
                    269: /*
                    270: ** A wrapper around ftruncate().
                    271: */
                    272: static int ts_ftruncate(int fd, off_t n){
                    273:   if( tsIsFailErrno("ftruncate") ){
                    274:     return -1;
                    275:   }
                    276:   return orig_ftruncate(fd, n);
                    277: }
                    278: 
                    279: /*
                    280: ** A wrapper around fcntl().
                    281: */
                    282: static int ts_fcntl(int fd, int cmd, ... ){
                    283:   va_list ap;
                    284:   void *pArg;
                    285:   if( tsIsFailErrno("fcntl") ){
                    286:     return -1;
                    287:   }
                    288:   va_start(ap, cmd);
                    289:   pArg = va_arg(ap, void *);
                    290:   return orig_fcntl(fd, cmd, pArg);
                    291: }
                    292: 
                    293: /*
                    294: ** A wrapper around read().
                    295: */
                    296: static int ts_read(int fd, void *aBuf, size_t nBuf){
                    297:   if( tsIsFailErrno("read") ){
                    298:     return -1;
                    299:   }
                    300:   return orig_read(fd, aBuf, nBuf);
                    301: }
                    302: 
                    303: /*
                    304: ** A wrapper around pread().
                    305: */
                    306: static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off){
                    307:   if( tsIsFailErrno("pread") ){
                    308:     return -1;
                    309:   }
                    310:   return orig_pread(fd, aBuf, nBuf, off);
                    311: }
                    312: 
                    313: /*
                    314: ** A wrapper around pread64().
                    315: */
                    316: static int ts_pread64(int fd, void *aBuf, size_t nBuf, off_t off){
                    317:   if( tsIsFailErrno("pread64") ){
                    318:     return -1;
                    319:   }
                    320:   return orig_pread64(fd, aBuf, nBuf, off);
                    321: }
                    322: 
                    323: /*
                    324: ** A wrapper around write().
                    325: */
                    326: static int ts_write(int fd, const void *aBuf, size_t nBuf){
                    327:   if( tsIsFailErrno("write") ){
                    328:     if( tsErrno("write")==EINTR ) orig_write(fd, aBuf, nBuf/2);
                    329:     return -1;
                    330:   }
                    331:   return orig_write(fd, aBuf, nBuf);
                    332: }
                    333: 
                    334: /*
                    335: ** A wrapper around pwrite().
                    336: */
                    337: static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off){
                    338:   if( tsIsFailErrno("pwrite") ){
                    339:     return -1;
                    340:   }
                    341:   return orig_pwrite(fd, aBuf, nBuf, off);
                    342: }
                    343: 
                    344: /*
                    345: ** A wrapper around pwrite64().
                    346: */
                    347: static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, off_t off){
                    348:   if( tsIsFailErrno("pwrite64") ){
                    349:     return -1;
                    350:   }
                    351:   return orig_pwrite64(fd, aBuf, nBuf, off);
                    352: }
                    353: 
                    354: /*
                    355: ** A wrapper around fchmod().
                    356: */
                    357: static int ts_fchmod(int fd, mode_t mode){
                    358:   if( tsIsFail() ){
                    359:     return -1;
                    360:   }
                    361:   return orig_fchmod(fd, mode);
                    362: }
                    363: 
                    364: /*
                    365: ** A wrapper around fallocate().
                    366: **
                    367: ** SQLite assumes that the fallocate() function is compatible with
                    368: ** posix_fallocate(). According to the Linux man page (2009-09-30):
                    369: **
                    370: **   posix_fallocate() returns  zero on success, or an error number on
                    371: **   failure. Note that errno is not set.
                    372: */
                    373: static int ts_fallocate(int fd, off_t off, off_t len){
                    374:   if( tsIsFail() ){
                    375:     return tsErrno("fallocate");
                    376:   }
                    377:   return orig_fallocate(fd, off, len);
                    378: }
                    379: 
                    380: static int test_syscall_install(
                    381:   void * clientData,
                    382:   Tcl_Interp *interp,
                    383:   int objc,
                    384:   Tcl_Obj *CONST objv[]
                    385: ){
                    386:   sqlite3_vfs *pVfs; 
                    387:   int nElem;
                    388:   int i;
                    389:   Tcl_Obj **apElem;
                    390: 
                    391:   if( objc!=3 ){
                    392:     Tcl_WrongNumArgs(interp, 2, objv, "SYSCALL-LIST");
                    393:     return TCL_ERROR;
                    394:   }
                    395:   if( Tcl_ListObjGetElements(interp, objv[2], &nElem, &apElem) ){
                    396:     return TCL_ERROR;
                    397:   }
                    398:   pVfs = sqlite3_vfs_find(0);
                    399: 
                    400:   for(i=0; i<nElem; i++){
                    401:     int iCall;
                    402:     int rc = Tcl_GetIndexFromObjStruct(interp, 
                    403:         apElem[i], aSyscall, sizeof(aSyscall[0]), "system-call", 0, &iCall
                    404:     );
                    405:     if( rc ) return rc;
                    406:     if( aSyscall[iCall].xOrig==0 ){
                    407:       aSyscall[iCall].xOrig = pVfs->xGetSystemCall(pVfs, aSyscall[iCall].zName);
                    408:       pVfs->xSetSystemCall(pVfs, aSyscall[iCall].zName, aSyscall[iCall].xTest);
                    409:     }
                    410:     aSyscall[iCall].custom_errno = aSyscall[iCall].default_errno;
                    411:   }
                    412: 
                    413:   return TCL_OK;
                    414: }
                    415: 
                    416: static int test_syscall_uninstall(
                    417:   void * clientData,
                    418:   Tcl_Interp *interp,
                    419:   int objc,
                    420:   Tcl_Obj *CONST objv[]
                    421: ){
                    422:   sqlite3_vfs *pVfs; 
                    423:   int i;
                    424: 
                    425:   if( objc!=2 ){
                    426:     Tcl_WrongNumArgs(interp, 2, objv, "");
                    427:     return TCL_ERROR;
                    428:   }
                    429: 
                    430:   pVfs = sqlite3_vfs_find(0);
                    431:   for(i=0; aSyscall[i].zName; i++){
                    432:     if( aSyscall[i].xOrig ){
                    433:       pVfs->xSetSystemCall(pVfs, aSyscall[i].zName, 0);
                    434:       aSyscall[i].xOrig = 0;
                    435:     }
                    436:   }
                    437:   return TCL_OK;
                    438: }
                    439: 
                    440: static int test_syscall_reset(
                    441:   void * clientData,
                    442:   Tcl_Interp *interp,
                    443:   int objc,
                    444:   Tcl_Obj *CONST objv[]
                    445: ){
                    446:   sqlite3_vfs *pVfs; 
                    447:   int i;
                    448:   int rc;
                    449: 
                    450:   if( objc!=2 && objc!=3 ){
                    451:     Tcl_WrongNumArgs(interp, 2, objv, "");
                    452:     return TCL_ERROR;
                    453:   }
                    454: 
                    455:   pVfs = sqlite3_vfs_find(0);
                    456:   if( objc==2 ){
                    457:     rc = pVfs->xSetSystemCall(pVfs, 0, 0);
                    458:     for(i=0; aSyscall[i].zName; i++) aSyscall[i].xOrig = 0;
                    459:   }else{
                    460:     int nFunc;
                    461:     char *zFunc = Tcl_GetStringFromObj(objv[2], &nFunc);
                    462:     rc = pVfs->xSetSystemCall(pVfs, Tcl_GetString(objv[2]), 0);
                    463:     for(i=0; rc==SQLITE_OK && aSyscall[i].zName; i++){
                    464:       if( strlen(aSyscall[i].zName)!=nFunc ) continue;
                    465:       if( memcmp(aSyscall[i].zName, zFunc, nFunc) ) continue;
                    466:       aSyscall[i].xOrig = 0;
                    467:     }
                    468:   }
                    469:   if( rc!=SQLITE_OK ){
                    470:     Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3TestErrorName(rc), -1));
                    471:     return TCL_ERROR;
                    472:   }
                    473: 
                    474:   Tcl_ResetResult(interp);
                    475:   return TCL_OK;
                    476: }
                    477: 
                    478: static int test_syscall_exists(
                    479:   void * clientData,
                    480:   Tcl_Interp *interp,
                    481:   int objc,
                    482:   Tcl_Obj *CONST objv[]
                    483: ){
                    484:   sqlite3_vfs *pVfs; 
                    485:   sqlite3_syscall_ptr x;
                    486: 
                    487:   if( objc!=3 ){
                    488:     Tcl_WrongNumArgs(interp, 2, objv, "");
                    489:     return TCL_ERROR;
                    490:   }
                    491: 
                    492:   pVfs = sqlite3_vfs_find(0);
                    493:   x = pVfs->xGetSystemCall(pVfs, Tcl_GetString(objv[2]));
                    494: 
                    495:   Tcl_SetObjResult(interp, Tcl_NewBooleanObj(x!=0));
                    496:   return TCL_OK;
                    497: }
                    498: 
                    499: static int test_syscall_fault(
                    500:   void * clientData,
                    501:   Tcl_Interp *interp,
                    502:   int objc,
                    503:   Tcl_Obj *CONST objv[]
                    504: ){
                    505:   int nCount = 0;
                    506:   int bPersist = 0;
                    507: 
                    508:   if( objc!=2 && objc!=4 ){
                    509:     Tcl_WrongNumArgs(interp, 2, objv, "?COUNT PERSIST?");
                    510:     return TCL_ERROR;
                    511:   }
                    512: 
                    513:   if( objc==4 ){
                    514:     if( Tcl_GetIntFromObj(interp, objv[2], &nCount)
                    515:      || Tcl_GetBooleanFromObj(interp, objv[3], &bPersist)
                    516:     ){
                    517:       return TCL_ERROR;
                    518:     }
                    519:   }
                    520: 
                    521:   Tcl_SetObjResult(interp, Tcl_NewIntObj(gSyscall.nFail));
                    522:   gSyscall.nCount = nCount;
                    523:   gSyscall.bPersist = bPersist;
                    524:   gSyscall.nFail = 0;
                    525:   return TCL_OK;
                    526: }
                    527: 
                    528: static int test_syscall_errno(
                    529:   void * clientData,
                    530:   Tcl_Interp *interp,
                    531:   int objc,
                    532:   Tcl_Obj *CONST objv[]
                    533: ){
                    534:   int iCall;
                    535:   int iErrno;
                    536:   int rc;
                    537: 
                    538:   struct Errno {
                    539:     const char *z;
                    540:     int i;
                    541:   } aErrno[] = {
                    542:     { "EACCES",    EACCES },
                    543:     { "EINTR",     EINTR },
                    544:     { "EIO",       EIO },
                    545:     { "EOVERFLOW", EOVERFLOW },
                    546:     { "ENOMEM",    ENOMEM },
                    547:     { "EAGAIN",    EAGAIN },
                    548:     { "ETIMEDOUT", ETIMEDOUT },
                    549:     { "EBUSY",     EBUSY },
                    550:     { "EPERM",     EPERM },
                    551:     { "EDEADLK",   EDEADLK },
                    552:     { "ENOLCK",    ENOLCK },
                    553:     { 0, 0 }
                    554:   };
                    555: 
                    556:   if( objc!=4 ){
                    557:     Tcl_WrongNumArgs(interp, 2, objv, "SYSCALL ERRNO");
                    558:     return TCL_ERROR;
                    559:   }
                    560: 
                    561:   rc = Tcl_GetIndexFromObjStruct(interp, 
                    562:       objv[2], aSyscall, sizeof(aSyscall[0]), "system-call", 0, &iCall
                    563:   );
                    564:   if( rc!=TCL_OK ) return rc;
                    565:   rc = Tcl_GetIndexFromObjStruct(interp, 
                    566:       objv[3], aErrno, sizeof(aErrno[0]), "errno", 0, &iErrno
                    567:   );
                    568:   if( rc!=TCL_OK ) return rc;
                    569: 
                    570:   aSyscall[iCall].custom_errno = aErrno[iErrno].i;
                    571:   return TCL_OK;
                    572: }
                    573: 
                    574: static int test_syscall_list(
                    575:   void * clientData,
                    576:   Tcl_Interp *interp,
                    577:   int objc,
                    578:   Tcl_Obj *CONST objv[]
                    579: ){
                    580:   const char *zSys;
                    581:   sqlite3_vfs *pVfs; 
                    582:   Tcl_Obj *pList;
                    583: 
                    584:   if( objc!=2 ){
                    585:     Tcl_WrongNumArgs(interp, 2, objv, "");
                    586:     return TCL_ERROR;
                    587:   }
                    588: 
                    589:   pVfs = sqlite3_vfs_find(0);
                    590:   pList = Tcl_NewObj();
                    591:   Tcl_IncrRefCount(pList);
                    592:   for(zSys = pVfs->xNextSystemCall(pVfs, 0); 
                    593:       zSys!=0;
                    594:       zSys = pVfs->xNextSystemCall(pVfs, zSys)
                    595:   ){
                    596:     Tcl_ListObjAppendElement(interp, pList, Tcl_NewStringObj(zSys, -1));
                    597:   }
                    598: 
                    599:   Tcl_SetObjResult(interp, pList);
                    600:   Tcl_DecrRefCount(pList);
                    601:   return TCL_OK;
                    602: }
                    603: 
                    604: static int test_syscall_defaultvfs(
                    605:   void * clientData,
                    606:   Tcl_Interp *interp,
                    607:   int objc,
                    608:   Tcl_Obj *CONST objv[]
                    609: ){
                    610:   sqlite3_vfs *pVfs; 
                    611: 
                    612:   if( objc!=2 ){
                    613:     Tcl_WrongNumArgs(interp, 2, objv, "");
                    614:     return TCL_ERROR;
                    615:   }
                    616: 
                    617:   pVfs = sqlite3_vfs_find(0);
                    618:   Tcl_SetObjResult(interp, Tcl_NewStringObj(pVfs->zName, -1));
                    619:   return TCL_OK;
                    620: }
                    621: 
                    622: static int test_syscall(
                    623:   void * clientData,
                    624:   Tcl_Interp *interp,
                    625:   int objc,
                    626:   Tcl_Obj *CONST objv[]
                    627: ){
                    628:   struct SyscallCmd {
                    629:     const char *zName;
                    630:     Tcl_ObjCmdProc *xCmd;
                    631:   } aCmd[] = {
                    632:     { "fault",      test_syscall_fault },
                    633:     { "install",    test_syscall_install },
                    634:     { "uninstall",  test_syscall_uninstall },
                    635:     { "reset",      test_syscall_reset },
                    636:     { "errno",      test_syscall_errno },
                    637:     { "exists",     test_syscall_exists },
                    638:     { "list",       test_syscall_list },
                    639:     { "defaultvfs", test_syscall_defaultvfs },
                    640:     { 0, 0 }
                    641:   };
                    642:   int iCmd;
                    643:   int rc;
                    644: 
                    645:   if( objc<2 ){
                    646:     Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
                    647:     return TCL_ERROR;
                    648:   }
                    649:   rc = Tcl_GetIndexFromObjStruct(interp, 
                    650:       objv[1], aCmd, sizeof(aCmd[0]), "sub-command", 0, &iCmd
                    651:   );
                    652:   if( rc!=TCL_OK ) return rc;
                    653:   return aCmd[iCmd].xCmd(clientData, interp, objc, objv);
                    654: }
                    655: 
                    656: int SqlitetestSyscall_Init(Tcl_Interp *interp){
                    657:   struct SyscallCmd {
                    658:     const char *zName;
                    659:     Tcl_ObjCmdProc *xCmd;
                    660:   } aCmd[] = {
                    661:     { "test_syscall",     test_syscall},
                    662:   };
                    663:   int i;
                    664: 
                    665:   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
                    666:     Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xCmd, 0, 0);
                    667:   }
                    668:   return TCL_OK;
                    669: }
                    670: #else
                    671: int SqlitetestSyscall_Init(Tcl_Interp *interp){
                    672:   return TCL_OK;
                    673: }
                    674: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>