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