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