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