Annotation of embedaddon/sqlite3/src/test_syscall.c, revision 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>