File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sqlite3 / src / test_syscall.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:04:17 2012 UTC (12 years, 8 months ago) by misho
Branches: sqlite3, MAIN
CVS tags: v3_7_10, HEAD
sqlite3

    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>