1
0

test_syscall.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  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 mmap
  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. #include "sqliteInt.h"
  72. #include "sqlite3.h"
  73. #include "tcl.h"
  74. #include <stdlib.h>
  75. #include <string.h>
  76. #include <assert.h>
  77. #if SQLITE_OS_UNIX
  78. /* From main.c */
  79. extern const char *sqlite3ErrName(int);
  80. #include <sys/mman.h>
  81. #include <sys/types.h>
  82. #include <errno.h>
  83. static struct TestSyscallGlobal {
  84. int bPersist; /* 1 for persistent errors, 0 for transient */
  85. int nCount; /* Fail after this many more calls */
  86. int nFail; /* Number of failures that have occurred */
  87. } gSyscall = { 0, 0 };
  88. static int ts_open(const char *, int, int);
  89. static int ts_close(int fd);
  90. static int ts_access(const char *zPath, int mode);
  91. static char *ts_getcwd(char *zPath, size_t nPath);
  92. static int ts_stat(const char *zPath, struct stat *p);
  93. static int ts_fstat(int fd, struct stat *p);
  94. static int ts_ftruncate(int fd, off_t n);
  95. static int ts_fcntl(int fd, int cmd, ... );
  96. static int ts_read(int fd, void *aBuf, size_t nBuf);
  97. static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off);
  98. static int ts_pread64(int fd, void *aBuf, size_t nBuf, off_t off);
  99. static int ts_write(int fd, const void *aBuf, size_t nBuf);
  100. static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off);
  101. static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, off_t off);
  102. static int ts_fchmod(int fd, mode_t mode);
  103. static int ts_fallocate(int fd, off_t off, off_t len);
  104. static void *ts_mmap(void *, size_t, int, int, int, off_t);
  105. static void *ts_mremap(void*, size_t, size_t, int, ...);
  106. struct TestSyscallArray {
  107. const char *zName;
  108. sqlite3_syscall_ptr xTest;
  109. sqlite3_syscall_ptr xOrig;
  110. int default_errno; /* Default value for errno following errors */
  111. int custom_errno; /* Current value for errno if error */
  112. } aSyscall[] = {
  113. /* 0 */ { "open", (sqlite3_syscall_ptr)ts_open, 0, EACCES, 0 },
  114. /* 1 */ { "close", (sqlite3_syscall_ptr)ts_close, 0, 0, 0 },
  115. /* 2 */ { "access", (sqlite3_syscall_ptr)ts_access, 0, 0, 0 },
  116. /* 3 */ { "getcwd", (sqlite3_syscall_ptr)ts_getcwd, 0, 0, 0 },
  117. /* 4 */ { "stat", (sqlite3_syscall_ptr)ts_stat, 0, 0, 0 },
  118. /* 5 */ { "fstat", (sqlite3_syscall_ptr)ts_fstat, 0, 0, 0 },
  119. /* 6 */ { "ftruncate", (sqlite3_syscall_ptr)ts_ftruncate, 0, EIO, 0 },
  120. /* 7 */ { "fcntl", (sqlite3_syscall_ptr)ts_fcntl, 0, EACCES, 0 },
  121. /* 8 */ { "read", (sqlite3_syscall_ptr)ts_read, 0, 0, 0 },
  122. /* 9 */ { "pread", (sqlite3_syscall_ptr)ts_pread, 0, 0, 0 },
  123. /* 10 */ { "pread64", (sqlite3_syscall_ptr)ts_pread64, 0, 0, 0 },
  124. /* 11 */ { "write", (sqlite3_syscall_ptr)ts_write, 0, 0, 0 },
  125. /* 12 */ { "pwrite", (sqlite3_syscall_ptr)ts_pwrite, 0, 0, 0 },
  126. /* 13 */ { "pwrite64", (sqlite3_syscall_ptr)ts_pwrite64, 0, 0, 0 },
  127. /* 14 */ { "fchmod", (sqlite3_syscall_ptr)ts_fchmod, 0, 0, 0 },
  128. /* 15 */ { "fallocate", (sqlite3_syscall_ptr)ts_fallocate, 0, 0, 0 },
  129. /* 16 */ { "mmap", (sqlite3_syscall_ptr)ts_mmap, 0, 0, 0 },
  130. /* 17 */ { "mremap", (sqlite3_syscall_ptr)ts_mremap, 0, 0, 0 },
  131. { 0, 0, 0, 0, 0 }
  132. };
  133. #define orig_open ((int(*)(const char *, int, int))aSyscall[0].xOrig)
  134. #define orig_close ((int(*)(int))aSyscall[1].xOrig)
  135. #define orig_access ((int(*)(const char*,int))aSyscall[2].xOrig)
  136. #define orig_getcwd ((char*(*)(char*,size_t))aSyscall[3].xOrig)
  137. #define orig_stat ((int(*)(const char*,struct stat*))aSyscall[4].xOrig)
  138. #define orig_fstat ((int(*)(int,struct stat*))aSyscall[5].xOrig)
  139. #define orig_ftruncate ((int(*)(int,off_t))aSyscall[6].xOrig)
  140. #define orig_fcntl ((int(*)(int,int,...))aSyscall[7].xOrig)
  141. #define orig_read ((ssize_t(*)(int,void*,size_t))aSyscall[8].xOrig)
  142. #define orig_pread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].xOrig)
  143. #define orig_pread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].xOrig)
  144. #define orig_write ((ssize_t(*)(int,const void*,size_t))aSyscall[11].xOrig)
  145. #define orig_pwrite ((ssize_t(*)(int,const void*,size_t,off_t))\
  146. aSyscall[12].xOrig)
  147. #define orig_pwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\
  148. aSyscall[13].xOrig)
  149. #define orig_fchmod ((int(*)(int,mode_t))aSyscall[14].xOrig)
  150. #define orig_fallocate ((int(*)(int,off_t,off_t))aSyscall[15].xOrig)
  151. #define orig_mmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[16].xOrig)
  152. #define orig_mremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[17].xOrig)
  153. /*
  154. ** This function is called exactly once from within each invocation of a
  155. ** system call wrapper in this file. It returns 1 if the function should
  156. ** fail, or 0 if it should succeed.
  157. */
  158. static int tsIsFail(void){
  159. gSyscall.nCount--;
  160. if( gSyscall.nCount==0 || (gSyscall.nFail && gSyscall.bPersist) ){
  161. gSyscall.nFail++;
  162. return 1;
  163. }
  164. return 0;
  165. }
  166. /*
  167. ** Return the current error-number value for function zFunc. zFunc must be
  168. ** the name of a system call in the aSyscall[] table.
  169. **
  170. ** Usually, the current error-number is the value that errno should be set
  171. ** to if the named system call fails. The exception is "fallocate". See
  172. ** comments above the implementation of ts_fallocate() for details.
  173. */
  174. static int tsErrno(const char *zFunc){
  175. int i;
  176. int nFunc = strlen(zFunc);
  177. for(i=0; aSyscall[i].zName; i++){
  178. if( strlen(aSyscall[i].zName)!=nFunc ) continue;
  179. if( memcmp(aSyscall[i].zName, zFunc, nFunc) ) continue;
  180. return aSyscall[i].custom_errno;
  181. }
  182. assert(0);
  183. return 0;
  184. }
  185. /*
  186. ** A wrapper around tsIsFail(). If tsIsFail() returns non-zero, set the
  187. ** value of errno before returning.
  188. */
  189. static int tsIsFailErrno(const char *zFunc){
  190. if( tsIsFail() ){
  191. errno = tsErrno(zFunc);
  192. return 1;
  193. }
  194. return 0;
  195. }
  196. /*
  197. ** A wrapper around open().
  198. */
  199. static int ts_open(const char *zFile, int flags, int mode){
  200. if( tsIsFailErrno("open") ){
  201. return -1;
  202. }
  203. return orig_open(zFile, flags, mode);
  204. }
  205. /*
  206. ** A wrapper around close().
  207. */
  208. static int ts_close(int fd){
  209. if( tsIsFail() ){
  210. /* Even if simulating an error, close the original file-descriptor.
  211. ** This is to stop the test process from running out of file-descriptors
  212. ** when running a long test. If a call to close() appears to fail, SQLite
  213. ** never attempts to use the file-descriptor afterwards (or even to close
  214. ** it a second time). */
  215. orig_close(fd);
  216. return -1;
  217. }
  218. return orig_close(fd);
  219. }
  220. /*
  221. ** A wrapper around access().
  222. */
  223. static int ts_access(const char *zPath, int mode){
  224. if( tsIsFail() ){
  225. return -1;
  226. }
  227. return orig_access(zPath, mode);
  228. }
  229. /*
  230. ** A wrapper around getcwd().
  231. */
  232. static char *ts_getcwd(char *zPath, size_t nPath){
  233. if( tsIsFail() ){
  234. return NULL;
  235. }
  236. return orig_getcwd(zPath, nPath);
  237. }
  238. /*
  239. ** A wrapper around stat().
  240. */
  241. static int ts_stat(const char *zPath, struct stat *p){
  242. if( tsIsFail() ){
  243. return -1;
  244. }
  245. return orig_stat(zPath, p);
  246. }
  247. /*
  248. ** A wrapper around fstat().
  249. */
  250. static int ts_fstat(int fd, struct stat *p){
  251. if( tsIsFailErrno("fstat") ){
  252. return -1;
  253. }
  254. return orig_fstat(fd, p);
  255. }
  256. /*
  257. ** A wrapper around ftruncate().
  258. */
  259. static int ts_ftruncate(int fd, off_t n){
  260. if( tsIsFailErrno("ftruncate") ){
  261. return -1;
  262. }
  263. return orig_ftruncate(fd, n);
  264. }
  265. /*
  266. ** A wrapper around fcntl().
  267. */
  268. static int ts_fcntl(int fd, int cmd, ... ){
  269. va_list ap;
  270. void *pArg;
  271. if( tsIsFailErrno("fcntl") ){
  272. return -1;
  273. }
  274. va_start(ap, cmd);
  275. pArg = va_arg(ap, void *);
  276. return orig_fcntl(fd, cmd, pArg);
  277. }
  278. /*
  279. ** A wrapper around read().
  280. */
  281. static int ts_read(int fd, void *aBuf, size_t nBuf){
  282. if( tsIsFailErrno("read") ){
  283. return -1;
  284. }
  285. return orig_read(fd, aBuf, nBuf);
  286. }
  287. /*
  288. ** A wrapper around pread().
  289. */
  290. static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off){
  291. if( tsIsFailErrno("pread") ){
  292. return -1;
  293. }
  294. return orig_pread(fd, aBuf, nBuf, off);
  295. }
  296. /*
  297. ** A wrapper around pread64().
  298. */
  299. static int ts_pread64(int fd, void *aBuf, size_t nBuf, off_t off){
  300. if( tsIsFailErrno("pread64") ){
  301. return -1;
  302. }
  303. return orig_pread64(fd, aBuf, nBuf, off);
  304. }
  305. /*
  306. ** A wrapper around write().
  307. */
  308. static int ts_write(int fd, const void *aBuf, size_t nBuf){
  309. if( tsIsFailErrno("write") ){
  310. if( tsErrno("write")==EINTR ) orig_write(fd, aBuf, nBuf/2);
  311. return -1;
  312. }
  313. return orig_write(fd, aBuf, nBuf);
  314. }
  315. /*
  316. ** A wrapper around pwrite().
  317. */
  318. static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off){
  319. if( tsIsFailErrno("pwrite") ){
  320. return -1;
  321. }
  322. return orig_pwrite(fd, aBuf, nBuf, off);
  323. }
  324. /*
  325. ** A wrapper around pwrite64().
  326. */
  327. static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, off_t off){
  328. if( tsIsFailErrno("pwrite64") ){
  329. return -1;
  330. }
  331. return orig_pwrite64(fd, aBuf, nBuf, off);
  332. }
  333. /*
  334. ** A wrapper around fchmod().
  335. */
  336. static int ts_fchmod(int fd, mode_t mode){
  337. if( tsIsFail() ){
  338. return -1;
  339. }
  340. return orig_fchmod(fd, mode);
  341. }
  342. /*
  343. ** A wrapper around fallocate().
  344. **
  345. ** SQLite assumes that the fallocate() function is compatible with
  346. ** posix_fallocate(). According to the Linux man page (2009-09-30):
  347. **
  348. ** posix_fallocate() returns zero on success, or an error number on
  349. ** failure. Note that errno is not set.
  350. */
  351. static int ts_fallocate(int fd, off_t off, off_t len){
  352. if( tsIsFail() ){
  353. return tsErrno("fallocate");
  354. }
  355. return orig_fallocate(fd, off, len);
  356. }
  357. static void *ts_mmap(
  358. void *pAddr,
  359. size_t nByte,
  360. int prot,
  361. int flags,
  362. int fd,
  363. off_t iOff
  364. ){
  365. if( tsIsFailErrno("mmap") ){
  366. return MAP_FAILED;
  367. }
  368. return orig_mmap(pAddr, nByte, prot, flags, fd, iOff);
  369. }
  370. static void *ts_mremap(void *a, size_t b, size_t c, int d, ...){
  371. va_list ap;
  372. void *pArg;
  373. if( tsIsFailErrno("mremap") ){
  374. return MAP_FAILED;
  375. }
  376. va_start(ap, d);
  377. pArg = va_arg(ap, void *);
  378. return orig_mremap(a, b, c, d, pArg);
  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. if( objc!=3 ){
  391. Tcl_WrongNumArgs(interp, 2, objv, "SYSCALL-LIST");
  392. return TCL_ERROR;
  393. }
  394. if( Tcl_ListObjGetElements(interp, objv[2], &nElem, &apElem) ){
  395. return TCL_ERROR;
  396. }
  397. pVfs = sqlite3_vfs_find(0);
  398. for(i=0; i<nElem; i++){
  399. int iCall;
  400. int rc = Tcl_GetIndexFromObjStruct(interp,
  401. apElem[i], aSyscall, sizeof(aSyscall[0]), "system-call", 0, &iCall
  402. );
  403. if( rc ) return rc;
  404. if( aSyscall[iCall].xOrig==0 ){
  405. aSyscall[iCall].xOrig = pVfs->xGetSystemCall(pVfs, aSyscall[iCall].zName);
  406. pVfs->xSetSystemCall(pVfs, aSyscall[iCall].zName, aSyscall[iCall].xTest);
  407. }
  408. aSyscall[iCall].custom_errno = aSyscall[iCall].default_errno;
  409. }
  410. return TCL_OK;
  411. }
  412. static int test_syscall_uninstall(
  413. void * clientData,
  414. Tcl_Interp *interp,
  415. int objc,
  416. Tcl_Obj *CONST objv[]
  417. ){
  418. sqlite3_vfs *pVfs;
  419. int i;
  420. if( objc!=2 ){
  421. Tcl_WrongNumArgs(interp, 2, objv, "");
  422. return TCL_ERROR;
  423. }
  424. pVfs = sqlite3_vfs_find(0);
  425. for(i=0; aSyscall[i].zName; i++){
  426. if( aSyscall[i].xOrig ){
  427. pVfs->xSetSystemCall(pVfs, aSyscall[i].zName, 0);
  428. aSyscall[i].xOrig = 0;
  429. }
  430. }
  431. return TCL_OK;
  432. }
  433. static int test_syscall_reset(
  434. void * clientData,
  435. Tcl_Interp *interp,
  436. int objc,
  437. Tcl_Obj *CONST objv[]
  438. ){
  439. sqlite3_vfs *pVfs;
  440. int i;
  441. int rc;
  442. if( objc!=2 && objc!=3 ){
  443. Tcl_WrongNumArgs(interp, 2, objv, "");
  444. return TCL_ERROR;
  445. }
  446. pVfs = sqlite3_vfs_find(0);
  447. if( objc==2 ){
  448. rc = pVfs->xSetSystemCall(pVfs, 0, 0);
  449. for(i=0; aSyscall[i].zName; i++) aSyscall[i].xOrig = 0;
  450. }else{
  451. int nFunc;
  452. char *zFunc = Tcl_GetStringFromObj(objv[2], &nFunc);
  453. rc = pVfs->xSetSystemCall(pVfs, Tcl_GetString(objv[2]), 0);
  454. for(i=0; rc==SQLITE_OK && aSyscall[i].zName; i++){
  455. if( strlen(aSyscall[i].zName)!=nFunc ) continue;
  456. if( memcmp(aSyscall[i].zName, zFunc, nFunc) ) continue;
  457. aSyscall[i].xOrig = 0;
  458. }
  459. }
  460. if( rc!=SQLITE_OK ){
  461. Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
  462. return TCL_ERROR;
  463. }
  464. Tcl_ResetResult(interp);
  465. return TCL_OK;
  466. }
  467. static int test_syscall_exists(
  468. void * clientData,
  469. Tcl_Interp *interp,
  470. int objc,
  471. Tcl_Obj *CONST objv[]
  472. ){
  473. sqlite3_vfs *pVfs;
  474. sqlite3_syscall_ptr x;
  475. if( objc!=3 ){
  476. Tcl_WrongNumArgs(interp, 2, objv, "");
  477. return TCL_ERROR;
  478. }
  479. pVfs = sqlite3_vfs_find(0);
  480. x = pVfs->xGetSystemCall(pVfs, Tcl_GetString(objv[2]));
  481. Tcl_SetObjResult(interp, Tcl_NewBooleanObj(x!=0));
  482. return TCL_OK;
  483. }
  484. static int test_syscall_fault(
  485. void * clientData,
  486. Tcl_Interp *interp,
  487. int objc,
  488. Tcl_Obj *CONST objv[]
  489. ){
  490. int nCount = 0;
  491. int bPersist = 0;
  492. if( objc!=2 && objc!=4 ){
  493. Tcl_WrongNumArgs(interp, 2, objv, "?COUNT PERSIST?");
  494. return TCL_ERROR;
  495. }
  496. if( objc==4 ){
  497. if( Tcl_GetIntFromObj(interp, objv[2], &nCount)
  498. || Tcl_GetBooleanFromObj(interp, objv[3], &bPersist)
  499. ){
  500. return TCL_ERROR;
  501. }
  502. }
  503. Tcl_SetObjResult(interp, Tcl_NewIntObj(gSyscall.nFail));
  504. gSyscall.nCount = nCount;
  505. gSyscall.bPersist = bPersist;
  506. gSyscall.nFail = 0;
  507. return TCL_OK;
  508. }
  509. static int test_syscall_errno(
  510. void * clientData,
  511. Tcl_Interp *interp,
  512. int objc,
  513. Tcl_Obj *CONST objv[]
  514. ){
  515. int iCall;
  516. int iErrno;
  517. int rc;
  518. struct Errno {
  519. const char *z;
  520. int i;
  521. } aErrno[] = {
  522. { "EACCES", EACCES },
  523. { "EINTR", EINTR },
  524. { "EIO", EIO },
  525. { "EOVERFLOW", EOVERFLOW },
  526. { "ENOMEM", ENOMEM },
  527. { "EAGAIN", EAGAIN },
  528. { "ETIMEDOUT", ETIMEDOUT },
  529. { "EBUSY", EBUSY },
  530. { "EPERM", EPERM },
  531. { "EDEADLK", EDEADLK },
  532. { "ENOLCK", ENOLCK },
  533. { 0, 0 }
  534. };
  535. if( objc!=4 ){
  536. Tcl_WrongNumArgs(interp, 2, objv, "SYSCALL ERRNO");
  537. return TCL_ERROR;
  538. }
  539. rc = Tcl_GetIndexFromObjStruct(interp,
  540. objv[2], aSyscall, sizeof(aSyscall[0]), "system-call", 0, &iCall
  541. );
  542. if( rc!=TCL_OK ) return rc;
  543. rc = Tcl_GetIndexFromObjStruct(interp,
  544. objv[3], aErrno, sizeof(aErrno[0]), "errno", 0, &iErrno
  545. );
  546. if( rc!=TCL_OK ) return rc;
  547. aSyscall[iCall].custom_errno = aErrno[iErrno].i;
  548. return TCL_OK;
  549. }
  550. static int test_syscall_list(
  551. void * clientData,
  552. Tcl_Interp *interp,
  553. int objc,
  554. Tcl_Obj *CONST objv[]
  555. ){
  556. const char *zSys;
  557. sqlite3_vfs *pVfs;
  558. Tcl_Obj *pList;
  559. if( objc!=2 ){
  560. Tcl_WrongNumArgs(interp, 2, objv, "");
  561. return TCL_ERROR;
  562. }
  563. pVfs = sqlite3_vfs_find(0);
  564. pList = Tcl_NewObj();
  565. Tcl_IncrRefCount(pList);
  566. for(zSys = pVfs->xNextSystemCall(pVfs, 0);
  567. zSys!=0;
  568. zSys = pVfs->xNextSystemCall(pVfs, zSys)
  569. ){
  570. Tcl_ListObjAppendElement(interp, pList, Tcl_NewStringObj(zSys, -1));
  571. }
  572. Tcl_SetObjResult(interp, pList);
  573. Tcl_DecrRefCount(pList);
  574. return TCL_OK;
  575. }
  576. static int test_syscall_defaultvfs(
  577. void * clientData,
  578. Tcl_Interp *interp,
  579. int objc,
  580. Tcl_Obj *CONST objv[]
  581. ){
  582. sqlite3_vfs *pVfs;
  583. if( objc!=2 ){
  584. Tcl_WrongNumArgs(interp, 2, objv, "");
  585. return TCL_ERROR;
  586. }
  587. pVfs = sqlite3_vfs_find(0);
  588. Tcl_SetObjResult(interp, Tcl_NewStringObj(pVfs->zName, -1));
  589. return TCL_OK;
  590. }
  591. static int test_syscall(
  592. void * clientData,
  593. Tcl_Interp *interp,
  594. int objc,
  595. Tcl_Obj *CONST objv[]
  596. ){
  597. struct SyscallCmd {
  598. const char *zName;
  599. Tcl_ObjCmdProc *xCmd;
  600. } aCmd[] = {
  601. { "fault", test_syscall_fault },
  602. { "install", test_syscall_install },
  603. { "uninstall", test_syscall_uninstall },
  604. { "reset", test_syscall_reset },
  605. { "errno", test_syscall_errno },
  606. { "exists", test_syscall_exists },
  607. { "list", test_syscall_list },
  608. { "defaultvfs", test_syscall_defaultvfs },
  609. { 0, 0 }
  610. };
  611. int iCmd;
  612. int rc;
  613. if( objc<2 ){
  614. Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
  615. return TCL_ERROR;
  616. }
  617. rc = Tcl_GetIndexFromObjStruct(interp,
  618. objv[1], aCmd, sizeof(aCmd[0]), "sub-command", 0, &iCmd
  619. );
  620. if( rc!=TCL_OK ) return rc;
  621. return aCmd[iCmd].xCmd(clientData, interp, objc, objv);
  622. }
  623. int SqlitetestSyscall_Init(Tcl_Interp *interp){
  624. struct SyscallCmd {
  625. const char *zName;
  626. Tcl_ObjCmdProc *xCmd;
  627. } aCmd[] = {
  628. { "test_syscall", test_syscall},
  629. };
  630. int i;
  631. for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
  632. Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xCmd, 0, 0);
  633. }
  634. return TCL_OK;
  635. }
  636. #else
  637. int SqlitetestSyscall_Init(Tcl_Interp *interp){
  638. return TCL_OK;
  639. }
  640. #endif