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