budb-prototypes-20090316
[openafs.git] / src / budb / database.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 RCSID
14     ("$Header$");
15
16 #ifdef AFS_NT40_ENV
17 #include <winsock2.h>
18 #else
19 #include <netinet/in.h>
20 #endif
21 #include <sys/types.h>
22 #include <afs/stds.h>
23 #include <ubik.h>
24 #include <afs/bubasics.h>
25 #include "budb_errs.h"
26 #include "database.h"
27 #include "error_macros.h"
28 #include "budb_prototypes.h"
29 #include "afs/audit.h"
30 #include <string.h>
31
32 int pollCount;
33 struct memoryDB db;             /* really allocate it here */
34
35 void
36 db_panic(char *reason)
37 {
38     LogError(0, "db_panic: %s\n", reason);
39     BUDB_EXIT(-1);
40 }
41
42 afs_int32
43 InitDB(void)
44 {
45     afs_int32 code;
46
47     pollCount = 0;
48
49     memset(&db, 0, sizeof(db));
50     Lock_Init(&db.lock);
51     if ((code = InitDBalloc()) || (code = InitDBhash()))
52         return code;
53     return 0;
54 }
55
56 /* package up seek and write into one procedure for ease of use */
57
58 /* dbwrite 
59  *      write a portion of the database
60  * entry:
61  *      pos - offset into the database (disk address). If this is in the
62  *              database header, then buff must be a ptr to a portion of
63  *              the in-core header
64  *      buff - the information to write
65  *      len - size of the write
66  */
67
68 afs_int32
69 dbwrite(struct ubik_trans *ut, afs_int32 pos, void *buff, afs_int32 len)
70 {
71     afs_int32 code = 0;
72
73     if (((pos < sizeof(db.h)) && (buff != (char *)&db.h + pos))
74         || (pos >= ntohl(db.h.eofPtr))) {
75         Log("dbwrite: Illegal attempt to write at location 0 or past EOF\n");
76         ERROR(BUDB_IO);
77     }
78
79     code = ubik_Seek(ut, 0, pos);
80     if (code) {
81         LogError(code, "dbwrite: ubik_Seek to %d failed\n", pos);
82         ERROR(code);
83     }
84     code = ubik_Write(ut, buff, len);
85     if (code) {
86         LogError(code, "dbwrite: ubik_Write failed\n");
87         ERROR(code);
88     }
89
90   error_exit:
91     if (((++pollCount) % 4) == 0) {     /* Poll every 4 reads/writes */
92 #ifndef AFS_PTHREAD_ENV
93         IOMGR_Poll();
94 #endif
95         pollCount = 0;
96     }
97     return code;
98 }
99
100 /* same thing for read */
101
102 afs_int32
103 dbread(struct ubik_trans *ut, afs_int32 pos, void *buff, afs_int32 len)
104 {
105     afs_int32 code = 0;
106
107     if (pos >= ntohl(db.h.eofPtr)) {
108         LogError(0, "dbread: Attempt to read @%d (past EOF)\n", pos);
109         ERROR(BUDB_IO);
110     }
111
112     code = ubik_Seek(ut, 0, pos);
113     if (code) {
114         LogError(code, "dbread: ubik_Seek to %d failed\n", pos);
115         ERROR(code);
116     }
117     code = ubik_Read(ut, buff, len);
118     if (code) {
119         LogError(code, "dbread: ubik_Read pos %d, buff %d, len %d\n", pos,
120                  buff, len);
121         ERROR(code);
122     }
123
124   error_exit:
125     if (((++pollCount) % 4) == 0) {     /* Poll every 4 reads/writes */
126 #ifndef AFS_PTHREAD_ENV
127         IOMGR_Poll();
128 #endif
129         pollCount = 0;
130     }
131     return code;
132 }
133
134 /* Same as dbread excepts it does checking */
135 afs_int32
136 cdbread(struct ubik_trans *ut, int type, afs_int32 pos, void *buff, afs_int32 len)
137 {
138     afs_int32 code = 0;
139
140     code = checkDiskAddress(pos, type, 0, 0);
141     if (code) {
142         LogError(code, "cdbread: Bad Address for block %d (addr 0x%x)\n",
143                  type, pos);
144         ERROR(code);
145     }
146
147     code = ubik_Seek(ut, 0, pos);
148     if (code) {
149         LogError(code, "cdbread: ubik_Seek to 0x%x failed\n", pos);
150         ERROR(code);
151     }
152     code = ubik_Read(ut, buff, len);
153     if (code) {
154         LogError(code, "cdbread: ubik_Read pos 0x%x, buff %d, len %d\n", pos,
155                  buff, len);
156         ERROR(code);
157     }
158
159   error_exit:
160     if (((++pollCount) % 4) == 0) {     /* Poll every 4 reads/writes */
161 #ifndef AFS_PTHREAD_ENV
162         IOMGR_Poll();
163 #endif
164         pollCount = 0;
165     }
166     return code;
167 }
168
169 /* check that the database has been initialized.  Be careful to fail in a safe
170    manner, to avoid bogusly reinitializing the db.  */
171
172 afs_int32
173 CheckInit(struct ubik_trans *ut, 
174           int (*db_init) (struct ubik_trans *ut)) /* call if rebuilding DB */
175 {
176     register afs_int32 code;
177
178     /* Don't read header if not necessary */
179     if (!ubik_CacheUpdate(ut))
180         return 0;
181
182     ObtainWriteLock(&db.lock);
183
184     db.h.eofPtr = htonl(sizeof(db.h));  /* for sanity check in dbread */
185     code = dbread(ut, 0, (char *)&db.h, sizeof(db.h));
186     if (code)
187         ERROR(code);
188
189     if ((ntohl(db.h.version) != BUDB_VERSION)
190         || (ntohl(db.h.checkVersion) != BUDB_VERSION)) {
191
192         if ((ntohl(db.h.version) == 0) || (ntohl(db.h.checkVersion) == 0))
193             ERROR(BUDB_EMPTY);
194
195         LogError(0, "DB version should be %d; Initial = %d; Terminal = %d\n",
196                  BUDB_VERSION, ntohl(db.h.version), ntohl(db.h.checkVersion));
197         ERROR(BUDB_IO);
198     }
199
200     db.readTime = time(0);
201     ht_Reset(&db.volName);
202     ht_Reset(&db.tapeName);
203     ht_Reset(&db.dumpName);
204     ht_Reset(&db.dumpIden);
205
206   error_exit:
207     ReleaseWriteLock(&db.lock);
208     if (code) {
209         if ((code == UEOF) || (code == BUDB_EMPTY)) {
210             if (db_init) {
211                 LogDebug(0, "No data base - Building new one\n");
212
213                 /* try to write a good header */
214                 memset(&db.h, 0, sizeof(db.h));
215                 db.h.version = htonl(BUDB_VERSION);
216                 db.h.checkVersion = htonl(BUDB_VERSION);
217                 db.h.lastUpdate = db.h.lastDumpId = htonl(time(0));
218                 db.h.eofPtr = htonl(sizeof(db.h));
219
220                 /* text ptrs cleared by bzero */
221                 ht_DBInit();
222
223                 code = dbwrite(ut, 0, (char *)&db.h, sizeof(db.h));
224                 if (code)
225                     code = BUDB_IO;     /* return the error code */
226                 else
227                     code = db_init(ut); /* initialize the db */
228             } else {
229                 LogDebug(0, "No data base\n");
230                 code = BUDB_EMPTY;
231             }
232         } else {
233             LogDebug(0, "I/O Error\n");
234             code = BUDB_IO;
235         }
236     }
237     return code;
238 }