1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Code to maintain the runtime and on-disk filehandle mapping table for 31 * nfslog. 32 */ 33 34 #include <assert.h> 35 #include <errno.h> 36 #include <ctype.h> 37 #include <nfs/nfs.h> 38 #include <stdlib.h> 39 #include <stddef.h> 40 #include <string.h> 41 #include <strings.h> 42 #include <syslog.h> 43 #include <unistd.h> 44 #include <dirent.h> 45 #include <ndbm.h> 46 #include <time.h> 47 #include <libintl.h> 48 #include <sys/types.h> 49 #include <nfs/nfs.h> 50 #include <nfs/nfs_log.h> 51 #include "fhtab.h" 52 #include "nfslogd.h" 53 54 #define ROUNDUP32(val) (((val) + 3) & ~3) 55 56 /* 57 * It is important that this string not match the length of the 58 * file handle key length NFS_FHMAXDATA 59 */ 60 #define DB_VERSION_STRING "NFSLOG_DB_VERSION" 61 #define DB_VERSION "1" 62 63 #define MAX_PRUNE_REC_CNT 100000 64 65 fhandle_t public_fh = { 0 }; 66 67 struct db_list { 68 fsid_t fsid; /* filesystem fsid */ 69 char *path; /* dbm filepair path */ 70 DBM *db; /* open dbm database */ 71 bool_t getall; /* TRUE if all dbm for prefix open */ 72 struct db_list *next; /* next db */ 73 }; 74 75 static struct db_list *db_fs_list = NULL; 76 static char err_str[] = "DB I/O error has occured"; 77 struct link_keys { 78 fh_secondary_key lnkey; 79 int lnsize; 80 struct link_keys *next; 81 }; 82 extern int debug; 83 extern time_t mapping_update_interval; 84 extern time_t prune_timeout; 85 86 static int fill_link_key(char *linkkey, fhandle_t *dfh, char *name); 87 static struct db_list *db_get_db(char *fhpath, fsid_t *fsid, int *errorp, 88 int create_flag); 89 static struct db_list *db_get_all_databases(char *fhpath, bool_t getall); 90 static void debug_print_fhlist(FILE *fp, fhlist_ent *fhrecp); 91 static void debug_print_linkinfo(FILE *fp, linkinfo_ent *fhrecp); 92 static void debug_print_key(FILE *fp, char *str1, char *str2, char *key, 93 int ksize); 94 static void debug_print_key_and_data(FILE *fp, char *str1, char *str2, 95 char *key, int ksize, char *data, int dsize); 96 static int store_record(struct db_list *dbp, void *keyaddr, int keysize, 97 void *dataaddr, int datasize, char *str); 98 static void *fetch_record(struct db_list *dbp, void *keyaddr, int keysize, 99 void *dataaddr, int *errorp, char *str); 100 static int delete_record(struct db_list *dbp, void *keyaddr, int keysize, 101 char *str); 102 static int db_update_fhrec(struct db_list *dbp, void *keyaddr, int keysize, 103 fhlist_ent *fhrecp, char *str); 104 static int db_update_linkinfo(struct db_list *dbp, void *keyaddr, int keysize, 105 linkinfo_ent *linkp, char *str); 106 static fhlist_ent *create_primary_struct(struct db_list *dbp, fhandle_t *dfh, 107 char *name, fhandle_t *fh, uint_t flags, fhlist_ent *fhrecp, 108 int *errorp); 109 static fhlist_ent *db_add_primary(struct db_list *dbp, fhandle_t *dfh, 110 char *name, fhandle_t *fh, uint_t flags, fhlist_ent *fhrecp, 111 int *errorp); 112 static linkinfo_ent *get_next_link(struct db_list *dbp, char *linkkey, 113 int *linksizep, linkinfo_ent *linkp, void **cookiep, 114 int *errorp, char *msg); 115 static void free_link_cookies(void *cookie); 116 static void add_mc_path(struct db_list *dbp, fhandle_t *dfh, char *name, 117 fhlist_ent *fhrecp, linkinfo_ent *linkp, int *errorp); 118 static linkinfo_ent *create_link_struct(struct db_list *dbp, fhandle_t *dfh, 119 char *name, fhlist_ent *fhrecp, int *errorp); 120 static int db_add_secondary(struct db_list *dbp, fhandle_t *dfh, char *name, 121 fhandle_t *fh, fhlist_ent *fhrecp); 122 static linkinfo_ent *update_next_link(struct db_list *dbp, char *nextkey, 123 int nextsize, char *prevkey, int prevsize, int *errorp); 124 static int update_prev_link(struct db_list *dbp, char *nextkey, int nextsize, 125 char *prevkey, int prevsize); 126 static linkinfo_ent *update_linked_list(struct db_list *dbp, char *nextkey, 127 int nextsize, char *prevkey, int prevsize, int *errorp); 128 static int db_update_primary_new_head(struct db_list *dbp, 129 linkinfo_ent *dellinkp, linkinfo_ent *nextlinkp, fhlist_ent *fhrecp); 130 static int delete_link_by_key(struct db_list *dbp, char *linkkey, 131 int *linksizep, int *errorp, char *errstr); 132 static int delete_link(struct db_list *dbp, fhandle_t *dfh, char *name, 133 char *nextlinkkey, int *nextlinksizep, int *errorp, char *errstr); 134 135 /* 136 * The following functions do the actual database I/O. Currently use DBM. 137 */ 138 139 /* 140 * The "db_*" functions are functions that access the database using 141 * database-specific calls. Currently the only database supported is 142 * dbm. Because of the limitations of this database, in particular when 143 * it comes to manipulating records with the same key, or using multiple keys, 144 * the following design decisions have been made: 145 * 146 * Each file system has a separate dbm file, which are kept open as 147 * accessed, listed in a linked list. 148 * Two possible access mode are available for each file - either by 149 * file handle, or by directory file handle and name. Since 150 * dbm does not allow multiple keys, we will have a primary 151 * and secondary key for each file/link. 152 * The primary key is the pair (inode,gen) which can be obtained 153 * from the file handle. This points to a record with 154 * the full file handle and the secondary key (dfh-key,name) 155 * for one of the links. 156 * The secondary key is the pair (dfh-key,name) where dfh-key is 157 * the primary key for the directory and the name is the 158 * link name. It points to a record that contains the primary 159 * key for the file and to the previous and next hard link 160 * found for this file (if they exist). 161 * 162 * Summary of operations: 163 * Adding a new file: Create the primary record and secondary (link) 164 * record and add both to the database. The link record 165 * would have prev and next links set to NULL. 166 * 167 * Adding a link to a file in the database: Add the link record, 168 * to the head of the links list (i.e. prev = NULL, next = 169 * secondary key recorded in the primary record). Update 170 * the primary record to point to the new link, and the 171 * secondary record for the old head of list to point to new. 172 * 173 * Deleting a file: Delete the link record. If it is the last link 174 * then mark the primary record as deleted but don't delete 175 * that one from the database (in case some clients still 176 * hold the file handle). If there are other links, and the 177 * deleted link is the head of the list (in the primary 178 * record), update the primary record with the new head. 179 * 180 * Renaming a file: Add the new link and then delete the old one. 181 * 182 * Lookup by file handle (read, write, lookup, etc.) - fetch primary rec. 183 * Lookup by dir info (delete, link, rename) - fetch secondary rec. 184 * 185 * XXX NOTE: The code is written single-threaded. To make it multi- 186 * threaded, the following considerations must be made: 187 * 1. Changes/access to the db list must be atomic. 188 * 2. Changes/access for a specific file handle must be atomic 189 * (example: deleting a link may affect up to 4 separate database 190 * entries: the deleted link, the prev and next links if exist, 191 * and the filehandle entry, if it points to the deleted link - 192 * these changes must be atomic). 193 */ 194 195 /* 196 * Create a link key given directory fh and name 197 */ 198 static int 199 fill_link_key(char *linkkey, fhandle_t *dfh, char *name) 200 { 201 int linksize, linksize32; 202 203 (void) memcpy(linkkey, &dfh->fh_data, dfh->fh_len); 204 (void) strcpy(&linkkey[dfh->fh_len], name); 205 linksize = dfh->fh_len + strlen(name) + 1; 206 linksize32 = ROUNDUP32(linksize); 207 if (linksize32 > linksize) 208 bzero(&linkkey[linksize], linksize32 - linksize); 209 return (linksize32); 210 } 211 212 /* 213 * db_get_db - gets the database for the filesystem, or creates one 214 * if none exists. Return the pointer for the database in *dbpp if success. 215 * Return 0 for success, error code otherwise. 216 */ 217 static struct db_list * 218 db_get_db(char *fhpath, fsid_t *fsid, int *errorp, int create_flag) 219 { 220 struct db_list *p, *newp; 221 char fsidstr[30]; 222 datum key, data; 223 224 *errorp = 0; 225 for (p = db_fs_list; 226 (p != NULL) && memcmp(&p->fsid, fsid, sizeof (*fsid)); 227 p = p->next); 228 if (p != NULL) { 229 /* Found it */ 230 return (p); 231 } 232 /* Create it */ 233 if ((newp = calloc(1, sizeof (*newp))) == NULL) { 234 *errorp = errno; 235 syslog(LOG_ERR, gettext( 236 "db_get_db: malloc db failed: Error %s"), 237 strerror(*errorp)); 238 return (NULL); 239 } 240 (void) sprintf(fsidstr, "%08x%08x", fsid->val[0], fsid->val[1]); 241 if ((newp->path = malloc(strlen(fhpath) + 2 + strlen(fsidstr))) 242 == NULL) { 243 *errorp = errno; 244 syslog(LOG_ERR, gettext( 245 "db_get_db: malloc dbpath failed: Error %s"), 246 strerror(*errorp)); 247 goto err_exit; 248 } 249 (void) sprintf(newp->path, "%s.%s", fhpath, fsidstr); 250 /* 251 * The open mode is masked by UMASK. 252 */ 253 if ((newp->db = dbm_open(newp->path, create_flag | O_RDWR, 0666)) 254 == NULL) { 255 *errorp = errno; 256 syslog(LOG_ERR, gettext( 257 "db_get_db: dbm_open db '%s' failed: Error %s"), 258 newp->path, strerror(*errorp)); 259 if (*errorp == 0) /* should not happen but may */ 260 *errorp = -1; 261 goto err_exit; 262 } 263 /* 264 * Add the version identifier (have to check first in the 265 * case the db exists) 266 */ 267 key.dptr = DB_VERSION_STRING; 268 key.dsize = strlen(DB_VERSION_STRING); 269 data = dbm_fetch(newp->db, key); 270 if (data.dptr == NULL) { 271 data.dptr = DB_VERSION; 272 data.dsize = strlen(DB_VERSION); 273 (void) dbm_store(newp->db, key, data, DBM_INSERT); 274 } 275 276 (void) memcpy(&newp->fsid, fsid, sizeof (*fsid)); 277 newp->next = db_fs_list; 278 db_fs_list = newp; 279 if (debug > 1) { 280 (void) printf("db_get_db: db %s opened\n", newp->path); 281 } 282 return (newp); 283 284 err_exit: 285 if (newp != NULL) { 286 if (newp->db != NULL) { 287 dbm_close(newp->db); 288 } 289 if (newp->path != NULL) { 290 free(newp->path); 291 } 292 free(newp); 293 } 294 return (NULL); 295 } 296 297 /* 298 * db_get_all_databases - gets the database for any filesystem. This is used 299 * when any database will do - typically to retrieve the path for the 300 * public filesystem. If any database is open - return the first one, 301 * otherwise, search for it using fhpath. If getall is TRUE, open all 302 * matching databases, and mark them (to indicate that all such were opened). 303 * Return the pointer for a matching database if success. 304 */ 305 static struct db_list * 306 db_get_all_databases(char *fhpath, bool_t getall) 307 { 308 char *dirptr, *fhdir, *fhpathname; 309 int len, error; 310 DIR *dirp; 311 struct dirent *dp; 312 fsid_t fsid; 313 struct db_list *dbp, *ret_dbp; 314 315 for (dbp = db_fs_list; dbp != NULL; dbp = dbp->next) { 316 if (strncmp(fhpath, dbp->path, strlen(fhpath)) == 0) 317 break; 318 } 319 if (dbp != NULL) { 320 /* 321 * if one database for that prefix is open, and either only 322 * one is needed, or already opened all such databases, 323 * return here without exhaustive search 324 */ 325 if (!getall || dbp->getall) 326 return (dbp); 327 } 328 if ((fhdir = strdup(fhpath)) == NULL) { 329 syslog(LOG_ERR, gettext( 330 "db_get_all_databases: strdup '%s' Error '%s*'"), 331 fhpath, strerror(errno)); 332 return (NULL); 333 } 334 fhpathname = NULL; 335 ret_dbp = NULL; 336 if ((dirptr = strrchr(fhdir, '/')) == NULL) { 337 /* no directory */ 338 goto exit; 339 } 340 if ((fhpathname = strdup(&dirptr[1])) == NULL) { 341 syslog(LOG_ERR, gettext( 342 "db_get_all_databases: strdup '%s' Error '%s*'"), 343 &dirptr[1], strerror(errno)); 344 goto exit; 345 } 346 /* Terminate fhdir string at last '/' */ 347 dirptr[1] = '\0'; 348 /* Search the directory */ 349 if (debug > 2) { 350 (void) printf("db_get_all_databases: search '%s' for '%s*'\n", 351 fhdir, fhpathname); 352 } 353 if ((dirp = opendir(fhdir)) == NULL) { 354 syslog(LOG_ERR, gettext( 355 "db_get_all_databases: opendir '%s' Error '%s*'"), 356 fhdir, strerror(errno)); 357 goto exit; 358 } 359 len = strlen(fhpathname); 360 while ((dp = readdir(dirp)) != NULL) { 361 if (strncmp(fhpathname, dp->d_name, len) == 0) { 362 dirptr = &dp->d_name[len + 1]; 363 if (*(dirptr - 1) != '.') { 364 continue; 365 } 366 (void) sscanf(dirptr, "%08lx%08lx", 367 (ulong_t *)&fsid.val[0], (ulong_t *)&fsid.val[1]); 368 dbp = db_get_db(fhpath, &fsid, &error, 0); 369 if (dbp != NULL) { 370 ret_dbp = dbp; 371 if (!getall) 372 break; 373 dbp->getall = TRUE; 374 } 375 } 376 } 377 (void) closedir(dirp); 378 exit: 379 if (fhpathname != NULL) 380 free(fhpathname); 381 if (fhdir != NULL) 382 free(fhdir); 383 return (ret_dbp); 384 } 385 386 static void 387 debug_print_key(FILE *fp, char *str1, char *str2, char *key, int ksize) 388 { 389 (void) fprintf(fp, "%s: %s key (%d) ", str1, str2, ksize); 390 debug_opaque_print(fp, key, ksize); 391 /* may be inode,name - try to print the fields */ 392 if (ksize >= NFS_FHMAXDATA) { 393 (void) fprintf(fp, ": inode "); 394 debug_opaque_print(fp, &key[2], sizeof (int)); 395 (void) fprintf(fp, ", gen "); 396 debug_opaque_print(fp, &key[2 + sizeof (int)], sizeof (int)); 397 if (ksize > NFS_FHMAXDATA) { 398 (void) fprintf(fp, ", name '%s'", &key[NFS_FHMAXDATA]); 399 } 400 } 401 (void) fprintf(fp, "\n"); 402 } 403 404 static void 405 debug_print_linkinfo(FILE *fp, linkinfo_ent *linkp) 406 { 407 if (linkp == NULL) 408 return; 409 (void) fprintf(fp, "linkinfo:\ndfh: "); 410 debug_opaque_print(fp, (void *)&linkp->dfh, sizeof (linkp->dfh)); 411 (void) fprintf(fp, "\nname: '%s'", LN_NAME(linkp)); 412 (void) fprintf(fp, "\nmtime 0x%x, atime 0x%x, flags 0x%x, reclen %d\n", 413 linkp->mtime, linkp->atime, linkp->flags, linkp->reclen); 414 (void) fprintf(fp, "offsets: fhkey %d, name %d, next %d, prev %d\n", 415 linkp->fhkey_offset, linkp->name_offset, linkp->next_offset, 416 linkp->prev_offset); 417 debug_print_key(fp, "fhkey", "", LN_FHKEY(linkp), LN_FHKEY_LEN(linkp)); 418 debug_print_key(fp, "next", "", LN_NEXT(linkp), LN_NEXT_LEN(linkp)); 419 debug_print_key(fp, "prev", "", LN_PREV(linkp), LN_PREV_LEN(linkp)); 420 } 421 422 static void 423 debug_print_fhlist(FILE *fp, fhlist_ent *fhrecp) 424 { 425 if (fhrecp == NULL) 426 return; 427 (void) fprintf(fp, "fhrec:\nfh: "); 428 debug_opaque_print(fp, (void *)&fhrecp->fh, sizeof (fhrecp->fh)); 429 (void) fprintf(fp, "name '%s', dfh: ", fhrecp->name); 430 debug_opaque_print(fp, (void *)&fhrecp->dfh, sizeof (fhrecp->dfh)); 431 (void) fprintf(fp, "\nmtime 0x%x, atime 0x%x, flags 0x%x, reclen %d\n", 432 fhrecp->mtime, fhrecp->atime, fhrecp->flags, fhrecp->reclen); 433 } 434 435 static void 436 debug_print_key_and_data(FILE *fp, char *str1, char *str2, char *key, 437 int ksize, char *data, int dsize) 438 { 439 debug_print_key(fp, str1, str2, key, ksize); 440 (void) fprintf(fp, " ==> (%p,%d)\n", (void *)data, dsize); 441 if (ksize > NFS_FHMAXDATA) { 442 linkinfo_ent inf; 443 /* probably a link struct */ 444 (void) memcpy(&inf, data, sizeof (linkinfo_ent)); 445 debug_print_linkinfo(fp, &inf); 446 } else if (ksize == NFS_FHMAXDATA) { 447 fhlist_ent inf; 448 /* probably an fhlist struct */ 449 (void) memcpy(&inf, data, sizeof (linkinfo_ent)); 450 debug_print_fhlist(fp, &inf); 451 } else { 452 /* don't know... */ 453 debug_opaque_print(fp, data, dsize); 454 } 455 } 456 457 /* 458 * store_record - store the record in the database and return 0 for success 459 * or error code otherwise. 460 */ 461 static int 462 store_record(struct db_list *dbp, void *keyaddr, int keysize, void *dataaddr, 463 int datasize, char *str) 464 { 465 datum key, data; 466 int error; 467 char *errfmt = "store_record: dbm_store failed, Error: %s\n"; 468 char *err; 469 470 errno = 0; 471 key.dptr = keyaddr; 472 key.dsize = keysize; 473 data.dptr = dataaddr; 474 data.dsize = datasize; 475 476 if (debug > 2) { 477 debug_print_key_and_data(stdout, str, "dbm_store:\n ", 478 key.dptr, key.dsize, data.dptr, data.dsize); 479 } 480 if (dbm_store(dbp->db, key, data, DBM_REPLACE) < 0) { 481 /* Could not store */ 482 error = dbm_error(dbp->db); 483 dbm_clearerr(dbp->db); 484 485 if (error) { 486 if (errno) 487 err = strerror(errno); 488 else { 489 err = err_str; 490 errno = EIO; 491 } 492 } else { /* should not happen but sometimes does */ 493 err = err_str; 494 errno = -1; 495 } 496 if (debug) { 497 debug_print_key(stderr, str, "store_record:" 498 "dbm_store:\n", key.dptr, key.dsize); 499 (void) fprintf(stderr, errfmt, err); 500 } else 501 syslog(LOG_ERR, gettext(errfmt), err); 502 return (errno); 503 } 504 return (0); 505 } 506 507 /* 508 * fetch_record - fetch the record from the database and return 0 for success 509 * and errno for failure. 510 * dataaddr is an optional valid address for the result. If dataaddr 511 * is non-null, then that memory is already alloc'd. Else, alloc it, and 512 * the caller must free the returned struct when done. 513 */ 514 static void * 515 fetch_record(struct db_list *dbp, void *keyaddr, int keysize, void *dataaddr, 516 int *errorp, char *str) 517 { 518 datum key, data; 519 char *errfmt = "fetch_record: dbm_fetch failed, Error: %s\n"; 520 char *err; 521 522 errno = 0; 523 *errorp = 0; 524 key.dptr = keyaddr; 525 key.dsize = keysize; 526 527 data = dbm_fetch(dbp->db, key); 528 if (data.dptr == NULL) { 529 /* primary record not in database */ 530 *errorp = dbm_error(dbp->db); 531 dbm_clearerr(dbp->db); 532 533 if (*errorp) { 534 if (errno) 535 err = strerror(errno); 536 else { 537 err = err_str; 538 errno = EIO; 539 } 540 } else { /* should not happen but sometimes does */ 541 err = err_str; 542 errno = -1; 543 } 544 *errorp = errno; 545 546 if (debug > 3) { 547 debug_print_key(stderr, str, "fetch_record:" 548 "dbm_fetch:\n", key.dptr, key.dsize); 549 (void) fprintf(stderr, errfmt, err); 550 } else 551 syslog(LOG_ERR, gettext(errfmt), err); 552 return (NULL); 553 } 554 555 /* copy to local struct because dbm may return non-aligned pointers */ 556 if ((dataaddr == NULL) && 557 ((dataaddr = malloc(data.dsize)) == NULL)) { 558 *errorp = errno; 559 syslog(LOG_ERR, gettext( 560 "%s: dbm_fetch - malloc %ld: Error %s"), 561 str, data.dsize, strerror(*errorp)); 562 return (NULL); 563 } 564 (void) memcpy(dataaddr, data.dptr, data.dsize); 565 if (debug > 3) { 566 debug_print_key_and_data(stdout, str, "fetch_record:" 567 "dbm_fetch:\n", key.dptr, key.dsize, 568 dataaddr, data.dsize); 569 } 570 *errorp = 0; 571 return (dataaddr); 572 } 573 574 /* 575 * delete_record - delete the record from the database and return 0 for success 576 * or error code for failure. 577 */ 578 static int 579 delete_record(struct db_list *dbp, void *keyaddr, int keysize, char *str) 580 { 581 datum key; 582 int error = 0; 583 char *errfmt = "delete_record: dbm_delete failed, Error: %s\n"; 584 char *err; 585 586 errno = 0; 587 key.dptr = keyaddr; 588 key.dsize = keysize; 589 590 if (debug > 2) { 591 debug_print_key(stdout, str, "delete_record:" 592 "dbm_delete:\n", key.dptr, key.dsize); 593 } 594 if (dbm_delete(dbp->db, key) < 0) { 595 error = dbm_error(dbp->db); 596 dbm_clearerr(dbp->db); 597 598 if (error) { 599 if (errno) 600 err = strerror(errno); 601 else { 602 err = err_str; 603 errno = EIO; 604 } 605 } else { /* should not happen but sometimes does */ 606 err = err_str; 607 errno = -1; 608 } 609 if (debug) { 610 debug_print_key(stderr, str, "delete_record:" 611 "dbm_delete:\n", key.dptr, key.dsize); 612 (void) fprintf(stderr, errfmt, err); 613 } else 614 syslog(LOG_ERR, gettext(errfmt), err); 615 } 616 return (errno); 617 } 618 619 /* 620 * db_update_fhrec - puts fhrec in db with updated atime if more than 621 * mapping_update_interval seconds passed. Return 0 if success, error otherwise. 622 */ 623 static int 624 db_update_fhrec(struct db_list *dbp, void *keyaddr, int keysize, 625 fhlist_ent *fhrecp, char *str) 626 { 627 time_t cur_time = time(0); 628 629 if (difftime(cur_time, fhrecp->atime) >= mapping_update_interval) { 630 fhrecp->atime = cur_time; 631 return (store_record(dbp, keyaddr, keysize, 632 fhrecp, fhrecp->reclen, str)); 633 } 634 return (0); 635 } 636 637 /* 638 * db_update_linkinfo - puts linkinfo in db with updated atime if more than 639 * mapping_update_interval seconds passed. Return 0 if success, error otherwise. 640 */ 641 static int 642 db_update_linkinfo(struct db_list *dbp, void *keyaddr, int keysize, 643 linkinfo_ent *linkp, char *str) 644 { 645 time_t cur_time = time(0); 646 647 if (difftime(cur_time, linkp->atime) >= mapping_update_interval) { 648 linkp->atime = cur_time; 649 return (store_record(dbp, keyaddr, keysize, 650 linkp, linkp->reclen, str)); 651 } 652 return (0); 653 } 654 655 /* 656 * create_primary_struct - add primary record to the database. 657 * Database must be open when this function is called. 658 * If success, return the added database entry. fhrecp may be used to 659 * provide an existing memory area, else malloc it. If failed, *errorp 660 * contains the error code and return NULL. 661 */ 662 static fhlist_ent * 663 create_primary_struct(struct db_list *dbp, fhandle_t *dfh, char *name, 664 fhandle_t *fh, uint_t flags, fhlist_ent *fhrecp, int *errorp) 665 { 666 int reclen, reclen1; 667 fhlist_ent *new_fhrecp = fhrecp; 668 669 reclen1 = offsetof(fhlist_ent, name) + strlen(name) + 1; 670 reclen = ROUNDUP32(reclen1); 671 if (fhrecp == NULL) { /* allocated the memory */ 672 if ((new_fhrecp = malloc(reclen)) == NULL) { 673 *errorp = errno; 674 syslog(LOG_ERR, gettext( 675 "create_primary_struct: malloc %d Error %s"), 676 reclen, strerror(*errorp)); 677 return (NULL); 678 } 679 } 680 /* Fill in the fields */ 681 (void) memcpy(&new_fhrecp->fh, fh, sizeof (*fh)); 682 (void) memcpy(&new_fhrecp->dfh, dfh, sizeof (*dfh)); 683 new_fhrecp->flags = flags; 684 if (dfh == &public_fh) 685 new_fhrecp->flags |= PUBLIC_PATH; 686 else 687 new_fhrecp->flags &= ~PUBLIC_PATH; 688 new_fhrecp->mtime = time(0); 689 new_fhrecp->atime = new_fhrecp->mtime; 690 (void) strcpy(new_fhrecp->name, name); 691 if (reclen1 < reclen) { 692 bzero((char *)((uintptr_t)new_fhrecp + reclen1), 693 reclen - reclen1); 694 } 695 new_fhrecp->reclen = reclen; 696 *errorp = store_record(dbp, &fh->fh_data, fh->fh_len, new_fhrecp, 697 new_fhrecp->reclen, "create_primary_struct"); 698 if (*errorp != 0) { 699 /* Could not store */ 700 if (fhrecp == NULL) /* caller did not supply pointer */ 701 free(new_fhrecp); 702 return (NULL); 703 } 704 return (new_fhrecp); 705 } 706 707 /* 708 * db_add_primary - add primary record to the database. 709 * If record already in and live, return it (even if for a different link). 710 * If in database but marked deleted, replace it. If not in database, add it. 711 * Database must be open when this function is called. 712 * If success, return the added database entry. fhrecp may be used to 713 * provide an existing memory area, else malloc it. If failed, *errorp 714 * contains the error code and return NULL. 715 */ 716 static fhlist_ent * 717 db_add_primary(struct db_list *dbp, fhandle_t *dfh, char *name, fhandle_t *fh, 718 uint_t flags, fhlist_ent *fhrecp, int *errorp) 719 { 720 fhlist_ent *new_fhrecp; 721 fh_primary_key fhkey; 722 723 if (debug > 2) 724 (void) printf("db_add_primary entered: name '%s'\n", name); 725 726 bcopy(&fh->fh_data, fhkey, fh->fh_len); 727 new_fhrecp = fetch_record(dbp, fhkey, fh->fh_len, (void *)fhrecp, 728 errorp, "db_add_primary"); 729 if (new_fhrecp != NULL) { 730 /* primary record is in the database */ 731 /* Update atime if needed */ 732 *errorp = db_update_fhrec(dbp, fhkey, fh->fh_len, new_fhrecp, 733 "db_add_primary put fhrec"); 734 if (debug > 2) 735 (void) printf("db_add_primary exits(2): name '%s'\n", 736 name); 737 return (new_fhrecp); 738 } 739 /* primary record not in database - create it */ 740 new_fhrecp = create_primary_struct(dbp, dfh, name, fh, flags, 741 fhrecp, errorp); 742 if (new_fhrecp == NULL) { 743 /* Could not store */ 744 if (debug > 2) 745 (void) printf( 746 "db_add_primary exits(1): name '%s' Error %s\n", 747 name, ((*errorp >= 0) ? strerror(*errorp) : 748 "Unknown")); 749 750 return (NULL); 751 } 752 if (debug > 2) 753 (void) printf("db_add_primary exits(0): name '%s'\n", name); 754 return (new_fhrecp); 755 } 756 757 /* 758 * get_next_link - get and check the next link in the chain. 759 * Re-use space if linkp param non-null. Also set *linkkey and *linksizep 760 * to values for next link (*linksizep set to 0 if last link). 761 * cookie is used to detect corrupted link entries XXXXXXX 762 * Return the link pointer or NULL if none. 763 */ 764 static linkinfo_ent * 765 get_next_link(struct db_list *dbp, char *linkkey, int *linksizep, 766 linkinfo_ent *linkp, void **cookiep, int *errorp, char *msg) 767 { 768 int linksize, nextsize; 769 char *nextkey; 770 linkinfo_ent *new_linkp = linkp; 771 struct link_keys *lnp; 772 773 linksize = *linksizep; 774 if (linksize == 0) 775 return (NULL); 776 *linksizep = 0; 777 new_linkp = fetch_record(dbp, linkkey, linksize, (void *)linkp, 778 errorp, msg); 779 if (new_linkp == NULL) 780 return (NULL); 781 782 /* Set linkkey to point to next record */ 783 nextsize = LN_NEXT_LEN(new_linkp); 784 if (nextsize == 0) 785 return (new_linkp); 786 787 /* Add this key to the cookie list */ 788 if ((lnp = malloc(sizeof (struct link_keys))) == NULL) { 789 syslog(LOG_ERR, gettext("get_next_key: malloc error %s\n"), 790 strerror(errno)); 791 if ((new_linkp != NULL) && (linkp == NULL)) 792 free(new_linkp); 793 return (NULL); 794 } 795 (void) memcpy(lnp->lnkey, linkkey, linksize); 796 lnp->lnsize = linksize; 797 lnp->next = *(struct link_keys **)cookiep; 798 *cookiep = (void *)lnp; 799 800 /* Make sure record does not point to itself or other internal loops */ 801 nextkey = LN_NEXT(new_linkp); 802 for (; lnp != NULL; lnp = lnp->next) { 803 if ((nextsize == lnp->lnsize) && (memcmp( 804 lnp->lnkey, nextkey, nextsize) == 0)) { 805 806 /* 807 * XXX This entry's next pointer points to 808 * itself. This is only a work-around, remove 809 * this check once bug 4203186 is fixed. 810 */ 811 if (debug) { 812 (void) fprintf(stderr, 813 "%s: get_next_link: last record invalid.\n", 814 msg); 815 debug_print_key_and_data(stderr, msg, 816 "invalid rec:\n ", linkkey, linksize, 817 (char *)new_linkp, new_linkp->reclen); 818 } 819 /* Return as if this is the last link */ 820 return (new_linkp); 821 } 822 } 823 (void) memcpy(linkkey, nextkey, nextsize); 824 *linksizep = nextsize; 825 return (new_linkp); 826 } 827 828 /* 829 * free_link_cookies - free the cookie list 830 */ 831 static void 832 free_link_cookies(void *cookie) 833 { 834 struct link_keys *dellnp, *lnp; 835 836 lnp = (struct link_keys *)cookie; 837 while (lnp != NULL) { 838 dellnp = lnp; 839 lnp = lnp->next; 840 free(dellnp); 841 } 842 } 843 844 /* 845 * add_mc_path - add a mc link to a file that has other links. Add it at end 846 * of linked list. Called when it's known there are other links. 847 */ 848 static void 849 add_mc_path(struct db_list *dbp, fhandle_t *dfh, char *name, 850 fhlist_ent *fhrecp, linkinfo_ent *linkp, int *errorp) 851 { 852 fh_secondary_key linkkey; 853 int linksize, len; 854 linkinfo_ent lastlink, *lastlinkp; 855 void *cookie; 856 857 linksize = fill_link_key(linkkey, &fhrecp->dfh, fhrecp->name); 858 cookie = NULL; 859 do { 860 lastlinkp = get_next_link(dbp, linkkey, &linksize, &lastlink, 861 &cookie, errorp, "add_mc_path"); 862 } while (linksize > 0); 863 free_link_cookies(cookie); 864 /* reached end of list */ 865 if (lastlinkp == NULL) { 866 /* nothing to do */ 867 if (debug > 1) { 868 (void) fprintf(stderr, "add_mc_path link is null\n"); 869 } 870 return; 871 } 872 /* Add new link after last link */ 873 /* 874 * next - link key for the next in the list - add at end so null. 875 * prev - link key for the previous link in the list. 876 */ 877 linkp->prev_offset = linkp->next_offset; /* aligned */ 878 linksize = fill_link_key(LN_PREV(linkp), &lastlinkp->dfh, 879 LN_NAME(lastlinkp)); 880 linkp->reclen = linkp->prev_offset + linksize; /* aligned */ 881 882 /* Add the link information to the database */ 883 linksize = fill_link_key(linkkey, dfh, name); 884 *errorp = store_record(dbp, linkkey, linksize, 885 linkp, linkp->reclen, "add_mc_path"); 886 if (*errorp != 0) 887 return; 888 889 /* Now update previous last link to point forward to new link */ 890 /* Copy prev link out since it's going to be overwritten */ 891 linksize = LN_PREV_LEN(lastlinkp); 892 (void) memcpy(linkkey, LN_PREV(lastlinkp), linksize); 893 /* Update previous last link to point to new one */ 894 len = fill_link_key(LN_NEXT(lastlinkp), dfh, name); 895 lastlinkp->prev_offset = lastlinkp->next_offset + len; /* aligned */ 896 (void) memcpy(LN_PREV(lastlinkp), linkkey, linksize); 897 lastlinkp->reclen = lastlinkp->prev_offset + linksize; 898 /* Update the link information to the database */ 899 linksize = fill_link_key(linkkey, &lastlinkp->dfh, LN_NAME(lastlinkp)); 900 *errorp = store_record(dbp, linkkey, linksize, 901 lastlinkp, lastlinkp->reclen, "add_mc_path prev"); 902 } 903 904 /* 905 * create_link_struct - create the secondary struct. 906 * (dfh,name) is the secondary key, fhrec is the primary record for the file 907 * and linkpp is a place holder for the record (could be null). 908 * Insert the record to the database. 909 * Return 0 if success, error otherwise. 910 */ 911 static linkinfo_ent * 912 create_link_struct(struct db_list *dbp, fhandle_t *dfh, char *name, 913 fhlist_ent *fhrecp, int *errorp) 914 { 915 fh_secondary_key linkkey; 916 int len, linksize; 917 linkinfo_ent *linkp; 918 919 if ((linkp = malloc(sizeof (linkinfo_ent))) == NULL) { 920 *errorp = errno; 921 syslog(LOG_ERR, gettext( 922 "create_link_struct: malloc failed: Error %s"), 923 strerror(*errorp)); 924 return (NULL); 925 } 926 if (dfh == &public_fh) 927 linkp->flags |= PUBLIC_PATH; 928 else 929 linkp->flags &= ~PUBLIC_PATH; 930 (void) memcpy(&linkp->dfh, dfh, sizeof (*dfh)); 931 linkp->mtime = time(0); 932 linkp->atime = linkp->mtime; 933 /* Calculate offsets of variable fields */ 934 /* fhkey - primary key (inode/gen) */ 935 /* name - component name (in directory dfh) */ 936 linkp->fhkey_offset = ROUNDUP32(offsetof(linkinfo_ent, varbuf)); 937 len = fill_link_key(LN_FHKEY(linkp), &fhrecp->fh, name); 938 linkp->name_offset = linkp->fhkey_offset + fhrecp->fh.fh_len; 939 linkp->next_offset = linkp->fhkey_offset + len; /* aligned */ 940 /* 941 * next - link key for the next link in the list - NULL if it's 942 * the first link. If this is the public fs, only one link allowed. 943 * Avoid setting a multi-component path as primary path, 944 * unless no choice. 945 */ 946 len = 0; 947 if (memcmp(&fhrecp->dfh, dfh, sizeof (*dfh)) || 948 strcmp(fhrecp->name, name)) { 949 /* different link than the one that's in the record */ 950 if (dfh == &public_fh) { 951 /* parent is public fh - either multi-comp or root */ 952 if (memcmp(&fhrecp->fh, &public_fh, 953 sizeof (public_fh))) { 954 /* multi-comp path */ 955 add_mc_path(dbp, dfh, name, fhrecp, linkp, 956 errorp); 957 if (*errorp != 0) { 958 free(linkp); 959 return (NULL); 960 } 961 return (linkp); 962 } 963 } else { 964 /* new link to a file with a different one already */ 965 len = fill_link_key(LN_NEXT(linkp), &fhrecp->dfh, 966 fhrecp->name); 967 } 968 } 969 /* 970 * prev - link key for the previous link in the list - since we 971 * always insert at the front of the list, it's always initially NULL. 972 */ 973 linkp->prev_offset = linkp->next_offset + len; /* aligned */ 974 linkp->reclen = linkp->prev_offset; 975 976 /* Add the link information to the database */ 977 linksize = fill_link_key(linkkey, dfh, name); 978 *errorp = store_record(dbp, linkkey, linksize, linkp, linkp->reclen, 979 "create_link_struct"); 980 if (*errorp != 0) { 981 free(linkp); 982 return (NULL); 983 } 984 return (linkp); 985 } 986 987 /* 988 * db_add_secondary - add secondary record to the database (for the directory 989 * information). 990 * Assumes this is a new link, not yet in the database, and that the primary 991 * record is already in. 992 * If fhrecp is non-null, then fhrecp is the primary record. 993 * Database must be open when this function is called. 994 * Return 0 if success, error code otherwise. 995 */ 996 static int 997 db_add_secondary(struct db_list *dbp, fhandle_t *dfh, char *name, 998 fhandle_t *fh, fhlist_ent *fhrecp) 999 { 1000 int nextsize, len, error; 1001 linkinfo_ent nextlink, *newlinkp, *nextlinkp; 1002 uint_t fhflags; 1003 char *nextaddr; 1004 fhlist_ent *new_fhrecp = fhrecp; 1005 fh_primary_key fhkey; 1006 1007 if (debug > 2) 1008 (void) printf("db_add_secondary entered: name '%s'\n", name); 1009 1010 bcopy(&fh->fh_data, fhkey, fh->fh_len); 1011 if (fhrecp == NULL) { 1012 /* Fetch the primary record */ 1013 new_fhrecp = fetch_record(dbp, fhkey, fh->fh_len, NULL, 1014 &error, "db_add_secondary primary"); 1015 if (new_fhrecp == NULL) { 1016 return (error); 1017 } 1018 } 1019 /* Update fhrec atime if needed */ 1020 error = db_update_fhrec(dbp, fhkey, fh->fh_len, new_fhrecp, 1021 "db_add_secondary primary"); 1022 fhflags = new_fhrecp->flags; 1023 /* now create and insert the secondary record */ 1024 newlinkp = create_link_struct(dbp, dfh, name, new_fhrecp, &error); 1025 if (fhrecp == NULL) { 1026 free(new_fhrecp); 1027 new_fhrecp = NULL; 1028 } 1029 if (newlinkp == NULL) { 1030 if (debug > 2) 1031 (void) printf("create_link_struct '%s' Error %s\n", 1032 name, ((error >= 0) ? strerror(error) : 1033 "Unknown")); 1034 return (error); 1035 } 1036 nextsize = LN_NEXT_LEN(newlinkp); 1037 if (nextsize == 0) { 1038 /* No next - can exit now */ 1039 if (debug > 2) 1040 (void) printf("db_add_secondary: no next link\n"); 1041 free(newlinkp); 1042 return (0); 1043 } 1044 1045 /* 1046 * Update the linked list to point to new head: replace head of 1047 * list in the primary record, then update previous secondary record 1048 * to point to new head 1049 */ 1050 new_fhrecp = create_primary_struct(dbp, dfh, name, fh, fhflags, 1051 new_fhrecp, &error); 1052 if (new_fhrecp == NULL) { 1053 if (debug > 2) 1054 (void) printf( 1055 "db_add_secondary: replace primary failed\n"); 1056 free(newlinkp); 1057 return (error); 1058 } else if (fhrecp == NULL) { 1059 free(new_fhrecp); 1060 } 1061 1062 /* 1063 * newlink is the new head of the list, with its "next" pointing to 1064 * the old head, and its "prev" pointing to NULL. We now need to 1065 * modify the "next" entry to have its "prev" point to the new entry. 1066 */ 1067 nextaddr = LN_NEXT(newlinkp); 1068 if (debug > 2) { 1069 debug_print_key(stderr, "db_add_secondary", "next key\n ", 1070 nextaddr, nextsize); 1071 } 1072 /* Get the next link entry from the database */ 1073 nextlinkp = fetch_record(dbp, nextaddr, nextsize, (void *)&nextlink, 1074 &error, "db_add_secondary next link"); 1075 if (nextlinkp == NULL) { 1076 if (debug > 2) 1077 (void) printf( 1078 "db_add_secondary: fetch next link failed\n"); 1079 free(newlinkp); 1080 return (error); 1081 } 1082 1083 /* 1084 * since the "prev" field is the only field to be changed, and it's 1085 * the last in the link record, we only need to modify it (and reclen). 1086 * Re-use link to update the next record. 1087 */ 1088 len = fill_link_key(LN_PREV(nextlinkp), dfh, name); 1089 nextlinkp->reclen = nextlinkp->prev_offset + len; 1090 error = store_record(dbp, nextaddr, nextsize, nextlinkp, 1091 nextlinkp->reclen, "db_add_secondary"); 1092 if (debug > 2) 1093 (void) printf( 1094 "db_add_secondary exits(%d): name '%s'\n", error, name); 1095 free(newlinkp); 1096 return (error); 1097 } 1098 1099 /* 1100 * Update the next link to point to the new prev. 1101 * Return 0 for success, error code otherwise. 1102 * If successful, and nextlinkpp is non-null, 1103 * *nextlinkpp contains the record for the next link, since 1104 * we may will it if the primary record should be updated. 1105 */ 1106 static linkinfo_ent * 1107 update_next_link(struct db_list *dbp, char *nextkey, int nextsize, 1108 char *prevkey, int prevsize, int *errorp) 1109 { 1110 linkinfo_ent *nextlinkp, *linkp1; 1111 1112 if ((nextlinkp = malloc(sizeof (linkinfo_ent))) == NULL) { 1113 *errorp = errno; 1114 syslog(LOG_ERR, gettext( 1115 "update_next_link: malloc next Error %s"), 1116 strerror(*errorp)); 1117 return (NULL); 1118 } 1119 linkp1 = nextlinkp; 1120 nextlinkp = fetch_record(dbp, nextkey, nextsize, nextlinkp, 1121 errorp, "update next"); 1122 /* if there is no next record - ok */ 1123 if (nextlinkp == NULL) { 1124 /* Return no error */ 1125 *errorp = 0; 1126 free(linkp1); 1127 return (NULL); 1128 } 1129 /* Set its prev to the prev of the deleted record */ 1130 nextlinkp->reclen = ROUNDUP32(nextlinkp->reclen - 1131 LN_PREV_LEN(nextlinkp) + prevsize); 1132 /* Change the len and set prev */ 1133 if (prevsize > 0) { 1134 (void) memcpy(LN_PREV(nextlinkp), prevkey, prevsize); 1135 } 1136 /* No other changes needed because prev is last field */ 1137 *errorp = store_record(dbp, nextkey, nextsize, nextlinkp, 1138 nextlinkp->reclen, "update_next"); 1139 if (*errorp != 0) { 1140 free(nextlinkp); 1141 nextlinkp = NULL; 1142 } 1143 return (nextlinkp); 1144 } 1145 1146 /* 1147 * Update the prev link to point to the new next. 1148 * Return 0 for success, error code otherwise. 1149 */ 1150 static int 1151 update_prev_link(struct db_list *dbp, char *nextkey, int nextsize, 1152 char *prevkey, int prevsize) 1153 { 1154 linkinfo_ent prevlink, *prevlinkp; 1155 int diff, error; 1156 1157 /* Update its next to the given one */ 1158 prevlinkp = fetch_record(dbp, prevkey, prevsize, &prevlink, &error, 1159 "update prev"); 1160 /* if error there is no next record - ok */ 1161 if (prevlinkp == NULL) { 1162 return (0); 1163 } 1164 diff = nextsize - LN_NEXT_LEN(prevlinkp); 1165 prevlinkp->reclen = ROUNDUP32(prevlinkp->reclen + diff); 1166 /* Change the len and set next - may push prev */ 1167 if (diff != 0) { 1168 char *ptr = LN_PREV(prevlinkp); 1169 1170 prevlinkp->prev_offset += diff; 1171 (void) memcpy(LN_PREV(prevlinkp), ptr, LN_PREV_LEN(prevlinkp)); 1172 } 1173 if (nextsize > 0) { 1174 (void) memcpy(LN_NEXT(prevlinkp), nextkey, nextsize); 1175 } 1176 /* Store updated record */ 1177 error = store_record(dbp, prevkey, prevsize, prevlinkp, 1178 prevlinkp->reclen, "update_prev"); 1179 return (error); 1180 } 1181 1182 /* 1183 * update_linked_list - update the next link to point back to prev, and vice 1184 * versa. Normally called by delete_link to drop the deleted link from the 1185 * linked list of hard links for the file. next and prev are the keys of next 1186 * and previous links for the deleted link in the list (could be NULL). 1187 * Return 0 for success, error code otherwise. 1188 * If successful, and nextlinkpp is non-null, 1189 * return the record for the next link, since 1190 * if the primary record should be updated we'll need it. In this case, 1191 * actually allocate the space for it because we can't tell otherwise. 1192 */ 1193 static linkinfo_ent * 1194 update_linked_list(struct db_list *dbp, char *nextkey, int nextsize, 1195 char *prevkey, int prevsize, int *errorp) 1196 { 1197 linkinfo_ent *nextlinkp = NULL; 1198 1199 *errorp = 0; 1200 if (nextsize > 0) { 1201 nextlinkp = update_next_link(dbp, nextkey, nextsize, 1202 prevkey, prevsize, errorp); 1203 if (nextlinkp == NULL) { 1204 /* not an error if no next link */ 1205 if (*errorp != 0) { 1206 if (debug > 1) { 1207 (void) fprintf(stderr, 1208 "update_next_link Error %s\n", 1209 ((*errorp >= 0) ? strerror(*errorp) : 1210 "Unknown")); 1211 } 1212 return (NULL); 1213 } 1214 } 1215 } 1216 if (prevsize > 0) { 1217 *errorp = update_prev_link(dbp, nextkey, nextsize, 1218 prevkey, prevsize); 1219 if (*errorp != 0) { 1220 if (debug > 1) { 1221 (void) fprintf(stderr, 1222 "update_prev_link Error %s\n", 1223 ((*errorp >= 0) ? strerror(*errorp) : 1224 "Unknown")); 1225 } 1226 if (nextlinkp != NULL) 1227 free(nextlinkp); 1228 nextlinkp = NULL; 1229 } 1230 } 1231 return (nextlinkp); 1232 } 1233 1234 /* 1235 * db_update_primary_new_head - Update a primary record that the head of 1236 * the list is deleted. Similar to db_add_primary, but the primary record 1237 * must exist, and is always replaced with one pointing to the new link, 1238 * unless it does not point to the deleted link. If the link we deleted 1239 * was the last link, the delete the primary record as well. 1240 * Return 0 for success, error code otherwise. 1241 */ 1242 static int 1243 db_update_primary_new_head(struct db_list *dbp, linkinfo_ent *dellinkp, 1244 linkinfo_ent *nextlinkp, fhlist_ent *fhrecp) 1245 { 1246 int error; 1247 char *name, *next_name; 1248 fhandle_t *dfh; 1249 fh_primary_key fhkey; 1250 1251 dfh = &dellinkp->dfh; 1252 name = LN_NAME(dellinkp); 1253 /* If the deleted link was not the head of the list, we are done */ 1254 if (memcmp(&fhrecp->dfh, dfh, sizeof (*dfh)) || 1255 strcmp(fhrecp->name, name)) { 1256 /* should never be here... */ 1257 if (debug > 1) { 1258 (void) fprintf(stderr, 1259 "db_update_primary_new_head: primary " 1260 "is for [%s,", name); 1261 debug_opaque_print(stderr, (void *)dfh, sizeof (*dfh)); 1262 (void) fprintf(stderr, "], not [%s,", fhrecp->name); 1263 debug_opaque_print(stderr, (void *)&fhrecp->dfh, 1264 sizeof (fhrecp->dfh)); 1265 (void) fprintf(stderr, "]\n"); 1266 } 1267 return (0); /* not head of list so done */ 1268 } 1269 /* Set the head to nextkey if exists. Otherwise, mark file as deleted */ 1270 bcopy(&fhrecp->fh.fh_data, fhkey, fhrecp->fh.fh_len); 1271 if (nextlinkp == NULL) { 1272 /* last link */ 1273 /* remove primary record from database */ 1274 (void) delete_record(dbp, 1275 fhkey, fhrecp->fh.fh_len, 1276 "db_update_primary_new_head: fh delete"); 1277 return (0); 1278 } else { 1279 /* 1280 * There are still "live" links, so update the primary record. 1281 */ 1282 next_name = LN_NAME(nextlinkp); 1283 fhrecp->reclen = ROUNDUP32(offsetof(fhlist_ent, name) + 1284 strlen(next_name) + 1); 1285 /* Replace link data with the info for the next link */ 1286 (void) memcpy(&fhrecp->dfh, &nextlinkp->dfh, 1287 sizeof (nextlinkp->dfh)); 1288 (void) strcpy(fhrecp->name, next_name); 1289 } 1290 /* not last link */ 1291 fhrecp->mtime = time(0); 1292 fhrecp->atime = fhrecp->mtime; 1293 error = store_record(dbp, 1294 fhkey, fhrecp->fh.fh_len, fhrecp, 1295 fhrecp->reclen, "db_update_primary_new_head: fh"); 1296 return (error); 1297 } 1298 1299 /* 1300 * Exported functions 1301 */ 1302 1303 /* 1304 * db_add - add record to the database. If dfh, fh and name are all here, 1305 * add both primary and secondary records. If fh is not available, don't 1306 * add anything... 1307 * Assumes this is a new file, not yet in the database and that the record 1308 * for fh is already in. 1309 * Return 0 for success, error code otherwise. 1310 */ 1311 int 1312 db_add(char *fhpath, fhandle_t *dfh, char *name, fhandle_t *fh, uint_t flags) 1313 { 1314 struct db_list *dbp = NULL; 1315 fhlist_ent fhrec, *fhrecp; 1316 int error = 0; 1317 1318 if (fh == NULL) { 1319 /* nothing to add */ 1320 return (EINVAL); 1321 } 1322 if (fh == &public_fh) { 1323 dbp = db_get_all_databases(fhpath, FALSE); 1324 } else { 1325 dbp = db_get_db(fhpath, &fh->fh_fsid, &error, O_CREAT); 1326 } 1327 for (; dbp != NULL; dbp = ((fh != &public_fh) ? NULL : dbp->next)) { 1328 if (debug > 3) { 1329 (void) printf("db_add: name '%s', db '%s'\n", 1330 name, dbp->path); 1331 } 1332 fhrecp = db_add_primary(dbp, dfh, name, fh, flags, 1333 &fhrec, &error); 1334 if (fhrecp == NULL) { 1335 continue; 1336 } 1337 if ((dfh == NULL) || (name == NULL)) { 1338 /* Can't add link information */ 1339 syslog(LOG_ERR, gettext( 1340 "db_add: dfh %p, name %p - invalid"), 1341 (void *)dfh, (void *)name); 1342 error = EINVAL; 1343 continue; 1344 } 1345 if (fh == &public_fh) { 1346 while ((fhrecp != NULL) && strcmp(name, fhrecp->name)) { 1347 /* Replace the public fh rather than add link */ 1348 error = db_delete_link(fhpath, dfh, 1349 fhrecp->name); 1350 fhrecp = db_add_primary(dbp, dfh, name, fh, 1351 flags, &fhrec, &error); 1352 } 1353 if (fhrecp == NULL) { 1354 continue; 1355 } 1356 } 1357 error = db_add_secondary(dbp, dfh, name, fh, fhrecp); 1358 if (fhrecp != &fhrec) { 1359 free(fhrecp); 1360 } 1361 } 1362 return (error); 1363 } 1364 1365 /* 1366 * db_lookup - search the database for the file identified by fh. 1367 * Return the entry in *fhrecpp if found, or NULL with error set otherwise. 1368 */ 1369 fhlist_ent * 1370 db_lookup(char *fhpath, fhandle_t *fh, fhlist_ent *fhrecp, int *errorp) 1371 { 1372 struct db_list *dbp; 1373 fh_primary_key fhkey; 1374 1375 if ((fhpath == NULL) || (fh == NULL) || (errorp == NULL)) { 1376 if (errorp != NULL) 1377 *errorp = EINVAL; 1378 return (NULL); 1379 } 1380 *errorp = 0; 1381 if (fh == &public_fh) { 1382 dbp = db_get_all_databases(fhpath, FALSE); 1383 } else { 1384 dbp = db_get_db(fhpath, &fh->fh_fsid, errorp, O_CREAT); 1385 } 1386 if (dbp == NULL) { 1387 /* Could not get or create database */ 1388 return (NULL); 1389 } 1390 bcopy(&fh->fh_data, fhkey, fh->fh_len); 1391 fhrecp = fetch_record(dbp, fhkey, fh->fh_len, fhrecp, 1392 errorp, "db_lookup"); 1393 /* Update fhrec atime if needed */ 1394 if (fhrecp != NULL) { 1395 *errorp = db_update_fhrec(dbp, fhkey, fh->fh_len, fhrecp, 1396 "db_lookup"); 1397 } 1398 return (fhrecp); 1399 } 1400 1401 /* 1402 * db_lookup_link - search the database for the file identified by (dfh,name). 1403 * If the link was found, use it to search for the primary record. 1404 * Return 0 and set the entry in *fhrecpp if found, return error otherwise. 1405 */ 1406 fhlist_ent * 1407 db_lookup_link(char *fhpath, fhandle_t *dfh, char *name, fhlist_ent *fhrecp, 1408 int *errorp) 1409 { 1410 struct db_list *dbp; 1411 fh_secondary_key linkkey; 1412 linkinfo_ent *linkp; 1413 int linksize, fhkeysize; 1414 char *fhkey; 1415 1416 if ((fhpath == NULL) || (dfh == NULL) || (name == NULL) || 1417 (errorp == NULL)) { 1418 if (errorp != NULL) 1419 *errorp = EINVAL; 1420 return (NULL); 1421 } 1422 *errorp = 0; 1423 if (dfh == &public_fh) { 1424 dbp = db_get_all_databases(fhpath, FALSE); 1425 } else { 1426 dbp = db_get_db(fhpath, &dfh->fh_fsid, errorp, O_CREAT); 1427 } 1428 if (dbp == NULL) { 1429 /* Could not get or create database */ 1430 return (NULL); 1431 } 1432 /* Get the link record */ 1433 linksize = fill_link_key(linkkey, dfh, name); 1434 linkp = fetch_record(dbp, linkkey, linksize, NULL, errorp, 1435 "db_lookup_link link"); 1436 if (linkp != NULL) { 1437 /* Now use link to search for fh entry */ 1438 fhkeysize = LN_FHKEY_LEN(linkp); 1439 fhkey = LN_FHKEY(linkp); 1440 fhrecp = fetch_record(dbp, fhkey, fhkeysize, 1441 (void *)fhrecp, errorp, "db_lookup_link fh"); 1442 /* Update fhrec atime if needed */ 1443 if (fhrecp != NULL) { 1444 *errorp = db_update_fhrec(dbp, fhkey, fhkeysize, fhrecp, 1445 "db_lookup_link fhrec"); 1446 } 1447 /* Update link atime if needed */ 1448 *errorp = db_update_linkinfo(dbp, linkkey, linksize, linkp, 1449 "db_lookup_link link"); 1450 free(linkp); 1451 } else { 1452 fhrecp = NULL; 1453 } 1454 return (fhrecp); 1455 } 1456 1457 /* 1458 * delete_link - delete the requested link from the database. If it's the 1459 * last link in the database for that file then remove the primary record 1460 * as well. *errorp contains the returned error code. 1461 * Return ENOENT if link not in database and 0 otherwise. 1462 */ 1463 static int 1464 delete_link_by_key(struct db_list *dbp, char *linkkey, int *linksizep, 1465 int *errorp, char *errstr) 1466 { 1467 int nextsize, prevsize, fhkeysize, linksize; 1468 char *nextkey, *prevkey, *fhkey; 1469 linkinfo_ent *dellinkp, *nextlinkp; 1470 fhlist_ent *fhrecp, fhrec; 1471 1472 *errorp = 0; 1473 linksize = *linksizep; 1474 /* Get the link record */ 1475 dellinkp = fetch_record(dbp, linkkey, linksize, NULL, errorp, errstr); 1476 if (dellinkp == NULL) { 1477 /* 1478 * Link not in database. 1479 */ 1480 if (debug > 2) { 1481 debug_print_key(stderr, errstr, 1482 "link not in database\n", 1483 linkkey, linksize); 1484 } 1485 *linksizep = 0; 1486 return (ENOENT); 1487 } 1488 /* 1489 * Possibilities: 1490 * 1. Normal case - only one link to delete: the link next and 1491 * prev should be NULL, and fhrec's name/dfh are same 1492 * as the link. Remove the link and fhrec. 1493 * 2. Multiple hard links, and the deleted link is the head of 1494 * the list. Remove the link and replace the link key in 1495 * the primary record to point to the new head. 1496 * 3. Multiple hard links, and the deleted link is not the 1497 * head of the list (not the same as in fhrec) - just 1498 * delete the link and update the previous and next records 1499 * in the links linked list. 1500 */ 1501 1502 /* Get next and prev keys for linked list updates */ 1503 nextsize = LN_NEXT_LEN(dellinkp); 1504 nextkey = ((nextsize > 0) ? LN_NEXT(dellinkp) : NULL); 1505 prevsize = LN_PREV_LEN(dellinkp); 1506 prevkey = ((prevsize > 0) ? LN_PREV(dellinkp) : NULL); 1507 /* Update the linked list for the file */ 1508 nextlinkp = update_linked_list(dbp, nextkey, nextsize, 1509 prevkey, prevsize, errorp); 1510 if ((nextlinkp == NULL) && (*errorp != 0)) { 1511 free(dellinkp); 1512 *linksizep = 0; 1513 return (0); 1514 } 1515 /* Delete link record */ 1516 *errorp = delete_record(dbp, linkkey, linksize, errstr); 1517 /* Get the primary key */ 1518 fhkeysize = LN_FHKEY_LEN(dellinkp); 1519 fhkey = LN_FHKEY(dellinkp); 1520 fhrecp = fetch_record(dbp, fhkey, fhkeysize, 1521 &fhrec, errorp, errstr); 1522 if (fhrecp == NULL) { 1523 /* Should never happen */ 1524 if (debug > 1) { 1525 debug_print_key(stderr, errstr, 1526 "fetch primary for ", linkkey, linksize); 1527 (void) fprintf(stderr, " Error %s\n", 1528 ((*errorp >= 0) ? strerror(*errorp) : "Unknown")); 1529 } 1530 } else if ((*errorp == 0) && (prevsize <= 0)) { 1531 /* This is the head of the list update primary record */ 1532 *errorp = db_update_primary_new_head(dbp, dellinkp, 1533 nextlinkp, fhrecp); 1534 } else { 1535 /* Update fhrec atime if needed */ 1536 *errorp = db_update_fhrec(dbp, fhkey, fhkeysize, fhrecp, 1537 errstr); 1538 } 1539 *linksizep = nextsize; 1540 if (nextsize > 0) 1541 (void) memcpy(linkkey, nextkey, nextsize); 1542 if (nextlinkp != NULL) 1543 free(nextlinkp); 1544 free(dellinkp); 1545 return (0); 1546 } 1547 1548 /* 1549 * delete_link - delete the requested link from the database. If it's the 1550 * last link in the database for that file then remove the primary record 1551 * as well. If nextlinkkey/sizep are non-null, copy the key and key size of 1552 * the next link in the chain into them (this would save a dbm_fetch op). 1553 * Return ENOENT if link not in database and 0 otherwise, with *errorp 1554 * containing the returned error if any from the delete_link ops. 1555 */ 1556 static int 1557 delete_link(struct db_list *dbp, fhandle_t *dfh, char *name, 1558 char *nextlinkkey, int *nextlinksizep, int *errorp, char *errstr) 1559 { 1560 int linkerr; 1561 1562 *errorp = 0; 1563 if ((nextlinkkey != NULL) && (nextlinksizep != NULL)) { 1564 *nextlinksizep = fill_link_key(nextlinkkey, dfh, name); 1565 linkerr = delete_link_by_key(dbp, nextlinkkey, nextlinksizep, 1566 errorp, errstr); 1567 } else { 1568 int linksize; 1569 fh_secondary_key linkkey; 1570 1571 linksize = fill_link_key(linkkey, dfh, name); 1572 linkerr = delete_link_by_key(dbp, linkkey, &linksize, 1573 errorp, errstr); 1574 } 1575 return (linkerr); 1576 } 1577 1578 /* 1579 * db_delete_link - search the database for the file system for link. 1580 * Delete the link from the database. If this is the "primary" link, 1581 * set the primary record for the next link. If it's the last one, 1582 * delete the primary record. 1583 * Return 0 for success, error code otherwise. 1584 */ 1585 int 1586 db_delete_link(char *fhpath, fhandle_t *dfh, char *name) 1587 { 1588 struct db_list *dbp; 1589 int error = 0; 1590 1591 if ((fhpath == NULL) || (dfh == NULL) || (name == NULL)) { 1592 return (EINVAL); 1593 } 1594 if (dfh == &public_fh) { 1595 dbp = db_get_all_databases(fhpath, TRUE); 1596 } else { 1597 dbp = db_get_db(fhpath, &dfh->fh_fsid, &error, O_CREAT); 1598 } 1599 for (; dbp != NULL; dbp = ((dfh == &public_fh) ? dbp->next : NULL)) { 1600 (void) delete_link(dbp, dfh, name, NULL, NULL, &error, 1601 "db_delete_link link"); 1602 } 1603 return (error); 1604 } 1605 1606 #ifdef DEBUG 1607 /* 1608 * db_delete - Deletes the fhrec corresponding to the fh. Use only 1609 * for repairing the fhtable, not for normal handling. 1610 * Return 0 for success, error code otherwise. 1611 */ 1612 int 1613 db_delete(char *fhpath, fhandle_t *fh) 1614 { 1615 struct db_list *dbp; 1616 int error = 0; 1617 1618 if ((fhpath == NULL) || (fh == NULL)) { 1619 return (EINVAL); 1620 } 1621 if (fh == &public_fh) { 1622 dbp = db_get_all_databases(fhpath, TRUE); 1623 } else { 1624 dbp = db_get_db(fhpath, &fh->fh_fsid, &error, O_CREAT); 1625 } 1626 for (; dbp != NULL; dbp = ((fh == &public_fh) ? dbp->next : NULL)) { 1627 /* Get the link record */ 1628 (void) delete_record(dbp, &fh->fh_data, fh->fh_len, 1629 "db_delete: fh delete"); 1630 } 1631 return (error); 1632 } 1633 #endif /* DEBUG */ 1634 1635 /* 1636 * db_rename_link - search the database for the file system for link. 1637 * Add the new link and delete the old link from the database. 1638 * Return 0 for success, error code otherwise. 1639 */ 1640 int 1641 db_rename_link(char *fhpath, fhandle_t *from_dfh, char *from_name, 1642 fhandle_t *to_dfh, char *to_name) 1643 { 1644 int error; 1645 struct db_list *dbp; 1646 fhlist_ent fhrec, *fhrecp; 1647 1648 if ((fhpath == NULL) || (from_dfh == NULL) || (from_name == NULL) || 1649 (to_dfh == NULL) || (to_name == NULL)) { 1650 return (EINVAL); 1651 } 1652 if (from_dfh == &public_fh) { 1653 dbp = db_get_all_databases(fhpath, FALSE); 1654 } else { 1655 dbp = db_get_db(fhpath, &from_dfh->fh_fsid, &error, O_CREAT); 1656 } 1657 for (; dbp != NULL; 1658 dbp = ((from_dfh != &public_fh) ? NULL : dbp->next)) { 1659 /* find existing link */ 1660 fhrecp = db_lookup_link(fhpath, from_dfh, from_name, &fhrec, 1661 &error); 1662 if (fhrecp == NULL) { 1663 /* Could not find the link */ 1664 continue; 1665 } 1666 /* Delete the old link (if last primary record not deleted) */ 1667 error = db_delete_link(fhpath, from_dfh, from_name); 1668 if (error == 0) { 1669 error = db_add(fhpath, to_dfh, to_name, &fhrecp->fh, 1670 fhrecp->flags); 1671 } 1672 } 1673 return (error); 1674 } 1675 1676 /* 1677 * db_print_all_keys: prints all keys for a given filesystem. If fsidp is 1678 * NULL, print for all filesystems covered by fhpath. 1679 */ 1680 void 1681 db_print_all_keys(char *fhpath, fsid_t *fsidp, FILE *fp) 1682 { 1683 struct db_list *dbp; 1684 datum key; 1685 int error, len; 1686 char strkey[NFS_FHMAXDATA + MAXNAMELEN]; 1687 db_record rec; 1688 void *ptr; 1689 1690 if ((fhpath == NULL) || 1691 ((fsidp != NULL) && (fsidp == &public_fh.fh_fsid))) 1692 return; 1693 if (fsidp == NULL) { 1694 (void) db_get_all_databases(fhpath, TRUE); 1695 dbp = db_fs_list; 1696 } else { 1697 dbp = db_get_db(fhpath, fsidp, &error, 0); 1698 } 1699 if (dbp == NULL) { 1700 /* Could not get or create database */ 1701 return; 1702 } 1703 len = strlen(fhpath); 1704 for (; dbp != NULL; dbp = ((fsidp != NULL) ? NULL : dbp->next)) { 1705 if (strncmp(fhpath, dbp->path, len)) 1706 continue; 1707 (void) fprintf(fp, 1708 "\nStart print database for fsid 0x%x 0x%x\n", 1709 dbp->fsid.val[0], dbp->fsid.val[1]); 1710 (void) fprintf(fp, "=============================\n"); 1711 for (key = dbm_firstkey(dbp->db); key.dptr != NULL; 1712 key = dbm_nextkey(dbp->db)) { 1713 (void) memcpy(strkey, key.dptr, key.dsize); 1714 debug_print_key(fp, "", "", strkey, key.dsize); 1715 if (debug < 2) 1716 continue; 1717 ptr = fetch_record(dbp, key.dptr, key.dsize, 1718 (void *)&rec, &error, "db_prt_keys"); 1719 if (ptr == NULL) 1720 continue; 1721 if (key.dsize == NFS_FHMAXDATA) { 1722 /* fhrec */ 1723 debug_print_fhlist(fp, &rec.fhlist_rec); 1724 } else if (key.dsize > NFS_FHMAXDATA) { 1725 /* linkinfo */ 1726 debug_print_linkinfo(fp, &rec.link_rec); 1727 } 1728 (void) fprintf(fp, "-----------------------------\n"); 1729 } 1730 (void) fprintf(fp, "End print database for fsid 0x%x 0x%x\n", 1731 dbp->fsid.val[0], dbp->fsid.val[1]); 1732 } 1733 } 1734 1735 void 1736 debug_opaque_print(FILE *fp, void *buf, int size) 1737 { 1738 int bufoffset = 0; 1739 char debug_str[200]; 1740 1741 if ((buf == NULL) || (size <= 0)) 1742 return; 1743 1744 nfslog_opaque_print_buf(buf, size, debug_str, &bufoffset, 200); 1745 (void) fprintf(fp, debug_str); 1746 } 1747 1748 /* 1749 * links_timedout() takes a primary records and searches all of its 1750 * links to see if they all have access times that are older than 1751 * the 'prune_timeout' value. TRUE if all links are old and FALSE 1752 * if there is just one link that has an access time which is recent. 1753 */ 1754 static int 1755 links_timedout(struct db_list *pdb, fhlist_ent *pfe, time_t ts) 1756 { 1757 fh_secondary_key linkkey; 1758 linkinfo_ent *linkp, link_st; 1759 int error; 1760 int linksize; 1761 void *cookie; 1762 1763 /* Get the link record */ 1764 linksize = fill_link_key(linkkey, &pfe->dfh, pfe->name); 1765 cookie = NULL; 1766 do { 1767 linkp = get_next_link(pdb, linkkey, &linksize, &link_st, 1768 &cookie, &error, "links_timedout"); 1769 if ((linkp != NULL) && 1770 (difftime(ts, linkp->atime) <= prune_timeout)) { 1771 /* update primary record to have an uptodate time */ 1772 pfe = fetch_record(pdb, (void *)&pfe->fh.fh_data, 1773 pfe->fh.fh_len, NULL, &error, 1774 "links_timedout"); 1775 if (pfe == NULL) { 1776 syslog(LOG_ERR, gettext( 1777 "links_timedout: fetch fhrec error %s\n"), 1778 strerror(error)); 1779 } else { 1780 if (difftime(pfe->atime, linkp->atime) < 0) { 1781 /* update fhrec atime */ 1782 pfe->atime = linkp->atime; 1783 (void) store_record(pdb, 1784 (void *)&pfe->fh.fh_data, 1785 pfe->fh.fh_len, pfe, 1786 pfe->reclen, "links_timedout"); 1787 } 1788 free(pfe); 1789 } 1790 free_link_cookies(cookie); 1791 return (FALSE); 1792 } 1793 } while (linksize > 0); 1794 1795 free_link_cookies(cookie); 1796 return (TRUE); 1797 } 1798 1799 /* 1800 * prune_dbs() will search all of the open databases looking for records 1801 * that have not been accessed in the last 'prune_timeout' seconds. 1802 * This search is done on the primary records and a list of potential 1803 * timeout candidates is built. The reason for doing this is to not 1804 * disturb the underlying dbm_firstkey()/dbm_nextkey() sequence; we 1805 * want to search all of the records in the database. 1806 * Once we have our candidate list built, we examine each of those 1807 * item's links to check if the links have been accessed within the 1808 * 'prune_timeout' seconds. If neither the primary nor any its links 1809 * have been accessed, then all of those records are removed/deleted 1810 * from the database. 1811 */ 1812 int 1813 prune_dbs(char *fhpath) 1814 { 1815 struct db_list *pdb; 1816 datum key; 1817 db_record *ptr; 1818 struct fhlist_ent *pfe; 1819 int error, linkerr, linksize; 1820 time_t cur_time = time(0); 1821 fh_secondary_key linkkey; 1822 struct thelist { 1823 struct thelist *next; 1824 db_record *ptr; 1825 } thelist, *ptl; 1826 int cnt = 0; 1827 1828 if (fhpath != NULL) 1829 (void) db_get_all_databases(fhpath, TRUE); 1830 1831 thelist.next = NULL; 1832 /* 1833 * Search each of the open databases 1834 */ 1835 for (pdb = db_fs_list; pdb; pdb = pdb->next) { 1836 do { 1837 /* Check each record in the database */ 1838 for (key = dbm_firstkey(pdb->db); key.dptr != NULL; 1839 key = dbm_nextkey(pdb->db)) { 1840 /* We're only interested in primary records */ 1841 if (key.dsize != NFS_FHMAXDATA) 1842 continue; /* probably a link record */ 1843 ptr = fetch_record(pdb, key.dptr, key.dsize, 1844 NULL, &error, "dump_db"); 1845 if (ptr == NULL) 1846 continue; 1847 /* 1848 * If this record is a primary record and it is 1849 * not an export point or a public file handle path, 1850 * check it for a ancient access time. 1851 */ 1852 if ((ptr->fhlist_rec.flags & 1853 (EXPORT_POINT | PUBLIC_PATH)) || 1854 (difftime(cur_time, ptr->fhlist_rec.atime) <= 1855 prune_timeout)) { 1856 /* Keep this record in the database */ 1857 free(ptr); 1858 } else { 1859 /* Found one? Save off info about it */ 1860 ptl = malloc(sizeof (struct thelist)); 1861 if (ptl == NULL) { 1862 syslog(LOG_ERR, gettext( 1863 "prune_dbs: malloc failed, error %s\n"), 1864 strerror(errno)); 1865 break; 1866 } 1867 ptl->ptr = ptr; 1868 ptl->next = thelist.next; 1869 thelist.next = ptl; 1870 cnt++; /* count how many records allocated */ 1871 if (cnt > MAX_PRUNE_REC_CNT) { 1872 /* Limit number of records malloc'd */ 1873 if (debug) 1874 (void) fprintf(stderr, 1875 "prune_dbs: halt search - too many records\n"); 1876 break; 1877 } 1878 } 1879 } 1880 1881 /* 1882 * Take the saved records and check their links to make 1883 * sure that they have not been accessed as well. 1884 */ 1885 for (ptl = thelist.next; ptl; ptl = thelist.next) { 1886 thelist.next = ptl->next; 1887 /* Everything timed out? */ 1888 pfe = &(ptl->ptr->fhlist_rec); 1889 if (links_timedout(pdb, pfe, cur_time)) { 1890 1891 /* 1892 * Iterate until we run out of links. 1893 * We have to do this since there can be 1894 * multiple links to a primary record and 1895 * we need to delete one at a time. 1896 */ 1897 /* Delete the link and get the next */ 1898 linkerr = delete_link(pdb, 1899 &pfe->dfh, pfe->name, linkkey, 1900 &linksize, &error, "dump_db"); 1901 while ((linksize > 0) && !(error || linkerr)) { 1902 /* Delete the link and get the next */ 1903 linkerr = delete_link_by_key(pdb, 1904 linkkey, &linksize, 1905 &error, "dump_db"); 1906 if (error || linkerr) { 1907 break; 1908 } 1909 } 1910 if (linkerr) { 1911 /* link not in database, primary is */ 1912 /* Should never happen */ 1913 if (debug > 1) { 1914 (void) fprintf(stderr, 1915 "prune_dbs: Error primary exists "); 1916 debug_opaque_print(stderr, 1917 (void *)&pfe->fh, 1918 sizeof (pfe->fh)); 1919 (void) fprintf(stderr, "\n"); 1920 } 1921 if (debug) 1922 syslog(LOG_ERR, gettext( 1923 "prune_dbs: Error primary exists\n")); 1924 (void) delete_record(pdb, 1925 &pfe->fh.fh_data, pfe->fh.fh_len, 1926 "prune_dbs: fh delete"); 1927 } 1928 } 1929 /* Make sure to free the pointers used in the list */ 1930 free(ptl->ptr); 1931 free(ptl); 1932 cnt--; 1933 } 1934 thelist.next = NULL; 1935 } while (key.dptr != NULL); 1936 } 1937 return (0); 1938 } 1939