1 /* 2 ** This utility program looks at an SQLite database and determines whether 3 ** or not it is locked, the kind of lock, and who is holding this lock. 4 ** 5 ** This only works on unix when the posix advisory locking method is used 6 ** (which is the default on unix) and when the PENDING_BYTE is in its 7 ** usual place. 8 */ 9 #include <sys/types.h> 10 #include <sys/stat.h> 11 #include <unistd.h> 12 #include <fcntl.h> 13 #include <string.h> 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <errno.h> 17 18 static void usage(const char *argv0){ 19 fprintf(stderr, "Usage: %s database\n", argv0); 20 exit(1); 21 } 22 23 /* Check for a conflicting lock. If one is found, print an this 24 ** on standard output using the format string given and return 1. 25 ** If there are no conflicting locks, return 0. 26 */ 27 static int isLocked( 28 int h, /* File descriptor to check */ 29 int type, /* F_RDLCK or F_WRLCK */ 30 unsigned int iOfst, /* First byte of the lock */ 31 unsigned int iCnt, /* Number of bytes in the lock range */ 32 const char *zType /* Type of lock */ 33 ){ 34 struct flock lk; 35 36 memset(&lk, 0, sizeof(lk)); 37 lk.l_type = type; 38 lk.l_whence = SEEK_SET; 39 lk.l_start = iOfst; 40 lk.l_len = iCnt; 41 if( fcntl(h, F_GETLK, &lk)==(-1) ){ 42 fprintf(stderr, "fcntl(%d) failed: errno=%d\n", h, errno); 43 exit(1); 44 } 45 if( lk.l_type==F_UNLCK ) return 0; 46 printf("%s lock held by %d\n", zType, (int)lk.l_pid); 47 return 1; 48 } 49 50 /* 51 ** Location of locking bytes in the database file 52 */ 53 #define PENDING_BYTE (0x40000000) 54 #define RESERVED_BYTE (PENDING_BYTE+1) 55 #define SHARED_FIRST (PENDING_BYTE+2) 56 #define SHARED_SIZE 510 57 58 /* 59 ** Lock locations for shared-memory locks used by WAL mode. 60 */ 61 #define SHM_BASE 120 62 #define SHM_WRITE SHM_BASE 63 #define SHM_CHECKPOINT (SHM_BASE+1) 64 #define SHM_RECOVER (SHM_BASE+2) 65 #define SHM_READ_FIRST (SHM_BASE+3) 66 #define SHM_READ_SIZE 5 67 68 69 int main(int argc, char **argv){ 70 int hDb; /* File descriptor for the open database file */ 71 int hShm; /* File descriptor for WAL shared-memory file */ 72 char *zShm; /* Name of the shared-memory file for WAL mode */ 73 ssize_t got; /* Bytes read from header */ 74 int isWal; /* True if in WAL mode */ 75 int nName; /* Length of filename */ 76 unsigned char aHdr[100]; /* Database header */ 77 int nLock = 0; /* Number of locks held */ 78 int i; /* Loop counter */ 79 80 if( argc!=2 ) usage(argv[0]); 81 hDb = open(argv[1], O_RDONLY, 0); 82 if( hDb<0 ){ 83 fprintf(stderr, "cannot open %s\n", argv[1]); 84 return 1; 85 } 86 87 /* Make sure we are dealing with an database file */ 88 got = read(hDb, aHdr, 100); 89 if( got!=100 || memcmp(aHdr, "SQLite format 3",16)!=0 ){ 90 fprintf(stderr, "not an SQLite database: %s\n", argv[1]); 91 exit(1); 92 } 93 94 /* First check for an exclusive lock */ 95 if( isLocked(hDb, F_RDLCK, SHARED_FIRST, SHARED_SIZE, "EXCLUSIVE") ){ 96 return 0; 97 } 98 isWal = aHdr[18]==2; 99 if( isWal==0 ){ 100 /* Rollback mode */ 101 if( isLocked(hDb, F_RDLCK, PENDING_BYTE, 1, "PENDING") ) return 0; 102 if( isLocked(hDb, F_RDLCK, RESERVED_BYTE, 1, "RESERVED") ) return 0; 103 if( isLocked(hDb, F_WRLCK, SHARED_FIRST, SHARED_SIZE, "SHARED") ){ 104 return 0; 105 } 106 }else{ 107 /* WAL mode */ 108 nName = (int)strlen(argv[1]); 109 zShm = malloc( nName + 100 ); 110 if( zShm==0 ){ 111 fprintf(stderr, "out of memory\n"); 112 exit(1); 113 } 114 memcpy(zShm, argv[1], nName); 115 memcpy(&zShm[nName], "-shm", 5); 116 hShm = open(zShm, O_RDONLY, 0); 117 if( hShm<0 ){ 118 fprintf(stderr, "cannot open %s\n", zShm); 119 return 1; 120 } 121 if( isLocked(hShm, F_RDLCK, SHM_RECOVER, 1, "WAL-RECOVERY") ){ 122 return 0; 123 } 124 nLock += isLocked(hShm, F_RDLCK, SHM_CHECKPOINT, 1, "WAL-CHECKPOINT"); 125 nLock += isLocked(hShm, F_RDLCK, SHM_WRITE, 1, "WAL-WRITE"); 126 for(i=0; i<SHM_READ_SIZE; i++){ 127 nLock += isLocked(hShm, F_WRLCK, SHM_READ_FIRST+i, 1, "WAL-READ"); 128 } 129 } 130 if( nLock==0 ){ 131 printf("file is not locked\n"); 132 } 133 return 0; 134 } 135