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