Retire the AFS_PTR_FMT macro
[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 %p, len %d\n",
112                  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 %p, len %d\n",
147                  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 }