00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "db_config.h"
00011
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 #include <stdlib.h>
00015 #include <string.h>
00016 #endif
00017
00018 #include "db_int.h"
00019 #include "dbinc/db_page.h"
00020 #include "dbinc/db_verify.h"
00021 #include "dbinc/db_am.h"
00022 #include "dbinc/db_shash.h"
00023 #include "dbinc/mp.h"
00024 #include "dbinc/qam.h"
00025
00026
00027
00028
00029
00030
00031
00032 int
00033 __qam_vrfy_meta(dbp, vdp, meta, pgno, flags)
00034 DB *dbp;
00035 VRFY_DBINFO *vdp;
00036 QMETA *meta;
00037 db_pgno_t pgno;
00038 u_int32_t flags;
00039 {
00040 DB_ENV *dbenv;
00041 QUEUE *qp;
00042 VRFY_PAGEINFO *pip;
00043 db_pgno_t *extents, extid, first, last;
00044 size_t len;
00045 int count, i, isbad, nextents, ret, t_ret;
00046 char *buf, **names;
00047
00048 COMPQUIET(count, 0);
00049
00050 dbenv = dbp->dbenv;
00051 qp = (QUEUE *)dbp->q_internal;
00052 extents = NULL;
00053 first = last = 0;
00054 buf = NULL;
00055 names = NULL;
00056
00057 if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
00058 return (ret);
00059 isbad = 0;
00060
00061
00062
00063
00064
00065 if (!F_ISSET(pip, VRFY_INCOMPLETE))
00066 EPRINT((dbenv, "Page %lu: queue databases must be one-per-file",
00067 (u_long)pgno));
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081 if (DB_ALIGN(meta->re_len + sizeof(QAMDATA) - 1, sizeof(u_int32_t)) *
00082 meta->rec_page + QPAGE_SZ(dbp) > dbp->pgsize) {
00083 EPRINT((dbenv,
00084 "Page %lu: queue record length %lu too high for page size and recs/page",
00085 (u_long)pgno, (u_long)meta->re_len));
00086 ret = DB_VERIFY_FATAL;
00087 goto err;
00088 } else {
00089
00090
00091
00092
00093
00094 vdp->re_pad = meta->re_pad;
00095 qp->re_pad = (int)meta->re_pad;
00096 qp->re_len = vdp->re_len = meta->re_len;
00097 qp->rec_page = vdp->rec_page = meta->rec_page;
00098 qp->page_ext = vdp->page_ext = meta->page_ext;
00099 }
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 if (F_ISSET(vdp, VRFY_QMETA_SET)) {
00114 isbad = 1;
00115 EPRINT((dbenv,
00116 "Page %lu: database contains multiple Queue metadata pages",
00117 (u_long)pgno));
00118 goto err;
00119 }
00120 F_SET(vdp, VRFY_QMETA_SET);
00121 qp->page_ext = meta->page_ext;
00122 dbp->pgsize = meta->dbmeta.pagesize;
00123 qp->q_meta = pgno;
00124 qp->q_root = pgno + 1;
00125 vdp->first_recno = meta->first_recno;
00126 vdp->last_recno = meta->cur_recno;
00127 if (qp->page_ext != 0) {
00128 first = QAM_RECNO_EXTENT(dbp, vdp->first_recno);
00129 last = QAM_RECNO_EXTENT(dbp, vdp->last_recno);
00130 }
00131
00132
00133
00134
00135
00136
00137
00138 if ((ret = __db_appname(dbenv,
00139 DB_APP_DATA, qp->dir, 0, NULL, &buf)) != 0)
00140 goto err;
00141 if ((ret = __os_dirlist(dbenv, buf, &names, &count)) != 0)
00142 goto err;
00143 __os_free(dbenv, buf);
00144 buf = NULL;
00145
00146 len = strlen(QUEUE_EXTENT_HEAD) + strlen(qp->name) + 1;
00147 if ((ret = __os_malloc(dbenv, len, &buf)) != 0)
00148 goto err;
00149 len = (size_t)snprintf(buf, len, QUEUE_EXTENT_HEAD, qp->name);
00150 for (i = nextents = 0; i < count; i++) {
00151 if (strncmp(names[i], buf, len) == 0) {
00152
00153 extid = (db_pgno_t)strtoul(&names[i][len], NULL, 10);
00154 if (qp->page_ext != 0 &&
00155 (last > first ?
00156 (extid >= first && extid <= last) :
00157 (extid >= first || extid <= last)))
00158 continue;
00159 if (extents == NULL && (ret = __os_malloc(
00160 dbenv, (size_t)(count - i) * sizeof(extid),
00161 &extents)) != 0)
00162 goto err;
00163 extents[nextents] = extid;
00164 nextents++;
00165 }
00166 }
00167 if (nextents > 0)
00168 __db_err(dbenv,
00169 "Warning: %d extra extent files found", nextents);
00170 vdp->nextents = nextents;
00171 vdp->extents = extents;
00172
00173 err: if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0)
00174 ret = t_ret;
00175 if (names != NULL)
00176 __os_dirfree(dbenv, names, count);
00177 if (buf != NULL)
00178 __os_free(dbenv, buf);
00179 if (ret != 0 && extents != NULL)
00180 __os_free(dbenv, extents);
00181 if (LF_ISSET(DB_SALVAGE) &&
00182 (t_ret = __db_salvage_markdone(vdp, pgno)) != 0 && ret == 0)
00183 ret = t_ret;
00184 return (ret == 0 && isbad == 1 ? DB_VERIFY_BAD : ret);
00185 }
00186
00187
00188
00189
00190
00191
00192
00193
00194 int
00195 __qam_vrfy_data(dbp, vdp, h, pgno, flags)
00196 DB *dbp;
00197 VRFY_DBINFO *vdp;
00198 QPAGE *h;
00199 db_pgno_t pgno;
00200 u_int32_t flags;
00201 {
00202 DB fakedb;
00203 struct __queue fakeq;
00204 QAMDATA *qp;
00205 db_recno_t i;
00206
00207
00208
00209
00210
00211
00212
00213
00214 fakedb.q_internal = &fakeq;
00215 fakedb.flags = dbp->flags;
00216 fakeq.re_len = vdp->re_len;
00217
00218 for (i = 0; i < vdp->rec_page; i++) {
00219 qp = QAM_GET_RECORD(&fakedb, h, i);
00220 if ((u_int8_t *)qp >= (u_int8_t *)h + dbp->pgsize) {
00221 EPRINT((dbp->dbenv,
00222 "Page %lu: queue record %lu extends past end of page",
00223 (u_long)pgno, (u_long)i));
00224 return (DB_VERIFY_BAD);
00225 }
00226
00227 if (qp->flags & ~(QAM_VALID | QAM_SET)) {
00228 EPRINT((dbp->dbenv,
00229 "Page %lu: queue record %lu has bad flags (%#lx)",
00230 (u_long)pgno, (u_long)i, (u_long)qp->flags));
00231 return (DB_VERIFY_BAD);
00232 }
00233 }
00234
00235 return (0);
00236 }
00237
00238
00239
00240
00241
00242
00243
00244 int
00245 __qam_vrfy_structure(dbp, vdp, flags)
00246 DB *dbp;
00247 VRFY_DBINFO *vdp;
00248 u_int32_t flags;
00249 {
00250 VRFY_PAGEINFO *pip;
00251 db_pgno_t i;
00252 int ret, isbad;
00253
00254 isbad = 0;
00255
00256 if ((ret = __db_vrfy_getpageinfo(vdp, PGNO_BASE_MD, &pip)) != 0)
00257 return (ret);
00258
00259 if (pip->type != P_QAMMETA) {
00260 EPRINT((dbp->dbenv,
00261 "Page %lu: queue database has no meta page",
00262 (u_long)PGNO_BASE_MD));
00263 isbad = 1;
00264 goto err;
00265 }
00266
00267 if ((ret = __db_vrfy_pgset_inc(vdp->pgset, 0)) != 0)
00268 goto err;
00269
00270 for (i = 1; i <= vdp->last_pgno; i++) {
00271
00272 if (!LF_ISSET(DB_SALVAGE))
00273 __db_vrfy_struct_feedback(dbp, vdp);
00274
00275 if ((ret = __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0 ||
00276 (ret = __db_vrfy_getpageinfo(vdp, i, &pip)) != 0)
00277 return (ret);
00278 if (!F_ISSET(pip, VRFY_IS_ALLZEROES) &&
00279 pip->type != P_QAMDATA) {
00280 EPRINT((dbp->dbenv,
00281 "Page %lu: queue database page of incorrect type %lu",
00282 (u_long)i, (u_long)pip->type));
00283 isbad = 1;
00284 goto err;
00285 } else if ((ret = __db_vrfy_pgset_inc(vdp->pgset, i)) != 0)
00286 goto err;
00287 }
00288
00289 err: if ((ret = __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0)
00290 return (ret);
00291 return (isbad == 1 ? DB_VERIFY_BAD : 0);
00292 }
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 int
00303 __qam_vrfy_walkqueue(dbp, vdp, handle, callback, flags)
00304 DB *dbp;
00305 VRFY_DBINFO *vdp;
00306 void *handle;
00307 int (*callback) __P((void *, const void *));
00308 u_int32_t flags;
00309 {
00310 DB_ENV *dbenv;
00311 PAGE *h;
00312 QUEUE *qp;
00313 VRFY_PAGEINFO *pip;
00314 db_pgno_t first, i, last, pg_ext, stop;
00315 int isbad, nextents, ret, t_ret;
00316
00317 COMPQUIET(h, NULL);
00318
00319 dbenv = dbp->dbenv;
00320 qp = dbp->q_internal;
00321 pip = NULL;
00322 pg_ext = qp->page_ext;
00323 isbad = ret = t_ret = 0;
00324
00325
00326 if (pg_ext == 0)
00327 return (0);
00328
00329 first = QAM_RECNO_PAGE(dbp, vdp->first_recno);
00330 last = QAM_RECNO_PAGE(dbp, vdp->last_recno);
00331
00332 i = first;
00333 if (first > last)
00334 stop = QAM_RECNO_PAGE(dbp, UINT32_MAX);
00335 else
00336 stop = last;
00337 nextents = vdp->nextents;
00338
00339
00340 begin: for (; i <= stop; i++) {
00341
00342
00343
00344
00345 if (LF_ISSET(DB_SALVAGE) && (__db_salvage_isdone(vdp, i) != 0))
00346 continue;
00347 if ((t_ret = __qam_fget(dbp, &i, 0, &h)) != 0) {
00348 if (t_ret == ENOENT || t_ret == DB_PAGE_NOTFOUND) {
00349 i += (pg_ext - ((i - 1) % pg_ext)) - 1;
00350 continue;
00351 }
00352
00353
00354
00355
00356
00357 if (LF_ISSET(DB_SALVAGE)) {
00358 if (ret == 0)
00359 ret = t_ret;
00360 continue;
00361 } else
00362 return (t_ret);
00363 }
00364
00365 if (LF_ISSET(DB_SALVAGE)) {
00366
00367
00368
00369
00370
00371 if ((t_ret = __db_salvage(dbp,
00372 vdp, i, h, handle, callback, flags)) != 0) {
00373 if (ret == 0)
00374 ret = t_ret;
00375 isbad = 1;
00376 }
00377 } else {
00378
00379
00380
00381
00382
00383
00384
00385
00386 if ((ret = __db_vrfy_common(dbp,
00387 vdp, h, i, flags)) == DB_VERIFY_BAD)
00388 isbad = 1;
00389 else if (ret != 0)
00390 goto err;
00391
00392 __db_vrfy_struct_feedback(dbp, vdp);
00393
00394 if ((ret = __db_vrfy_getpageinfo(vdp, i, &pip)) != 0)
00395 return (ret);
00396 if (F_ISSET(pip, VRFY_IS_ALLZEROES))
00397 goto put;
00398 if (pip->type != P_QAMDATA) {
00399 EPRINT((dbenv,
00400 "Page %lu: queue database page of incorrect type %lu",
00401 (u_long)i, (u_long)pip->type));
00402 isbad = 1;
00403 goto err;
00404 }
00405 if ((ret = __db_vrfy_pgset_inc(vdp->pgset, i)) != 0)
00406 goto err;
00407 if ((ret = __qam_vrfy_data(dbp, vdp,
00408 (QPAGE *)h, i, flags)) == DB_VERIFY_BAD)
00409 isbad = 1;
00410 else if (ret != 0)
00411 goto err;
00412
00413 put: if ((ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0)
00414 goto err;
00415 pip = NULL;
00416 }
00417
00418
00419 if ((t_ret = __qam_fput(dbp, i, h, 0)) != 0) {
00420 if (LF_ISSET(DB_SALVAGE)) {
00421 if (ret == 0)
00422 ret = t_ret;
00423 continue;
00424 } else
00425 return (t_ret);
00426 }
00427 }
00428
00429 if (first > last) {
00430 i = 1;
00431 stop = last;
00432 first = last;
00433 goto begin;
00434 }
00435
00436
00437
00438
00439
00440 if (LF_ISSET(DB_SALVAGE) && nextents != 0) {
00441 nextents--;
00442 i = 1 +
00443 vdp->extents[nextents] * vdp->page_ext;
00444 stop = i + vdp->page_ext;
00445 goto begin;
00446 }
00447
00448 if (0) {
00449 err: if ((t_ret = __qam_fput(dbp, i, h, 0)) != 0)
00450 return (ret == 0 ? t_ret : ret);
00451 if (pip != NULL &&
00452 (t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0)
00453 return (ret == 0 ? t_ret : ret);
00454 }
00455 return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD : ret);
00456 }
00457
00458
00459
00460
00461
00462
00463
00464
00465 int
00466 __qam_salvage(dbp, vdp, pgno, h, handle, callback, flags)
00467 DB *dbp;
00468 VRFY_DBINFO *vdp;
00469 db_pgno_t pgno;
00470 PAGE *h;
00471 void *handle;
00472 int (*callback) __P((void *, const void *));
00473 u_int32_t flags;
00474 {
00475 DBT dbt, key;
00476 QAMDATA *qp, *qep;
00477 db_recno_t recno;
00478 int ret, err_ret, t_ret;
00479 u_int32_t pagesize, qlen;
00480 u_int32_t i;
00481
00482 memset(&dbt, 0, sizeof(DBT));
00483 memset(&key, 0, sizeof(DBT));
00484
00485 err_ret = ret = 0;
00486
00487 pagesize = (u_int32_t)dbp->mpf->mfp->stat.st_pagesize;
00488 qlen = ((QUEUE *)dbp->q_internal)->re_len;
00489 dbt.size = qlen;
00490 key.data = &recno;
00491 key.size = sizeof(recno);
00492 recno = (pgno - 1) * QAM_RECNO_PER_PAGE(dbp) + 1;
00493 i = 0;
00494 qep = (QAMDATA *)((u_int8_t *)h + pagesize - qlen);
00495 for (qp = QAM_GET_RECORD(dbp, h, i); qp < qep;
00496 recno++, i++, qp = QAM_GET_RECORD(dbp, h, i)) {
00497 if (F_ISSET(qp, ~(QAM_VALID|QAM_SET)))
00498 continue;
00499 if (!F_ISSET(qp, QAM_SET))
00500 continue;
00501
00502 if (!LF_ISSET(DB_AGGRESSIVE) && !F_ISSET(qp, QAM_VALID))
00503 continue;
00504
00505 dbt.data = qp->data;
00506 if ((ret = __db_vrfy_prdbt(&key,
00507 0, " ", handle, callback, 1, vdp)) != 0)
00508 err_ret = ret;
00509
00510 if ((ret = __db_vrfy_prdbt(&dbt,
00511 0, " ", handle, callback, 0, vdp)) != 0)
00512 err_ret = ret;
00513 }
00514
00515 if ((t_ret = __db_salvage_markdone(vdp, pgno)) != 0)
00516 return (t_ret);
00517 return ((ret == 0 && err_ret != 0) ? err_ret : ret);
00518 }