1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * db_table.cc 24*7c478bd9Sstevel@tonic-gate * 25*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 26*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 27*7c478bd9Sstevel@tonic-gate */ 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #include <stdio.h> 32*7c478bd9Sstevel@tonic-gate #include <malloc.h> 33*7c478bd9Sstevel@tonic-gate #include <string.h> 34*7c478bd9Sstevel@tonic-gate #include <stdlib.h> /* srand48() */ 35*7c478bd9Sstevel@tonic-gate #include <lber.h> 36*7c478bd9Sstevel@tonic-gate #include <ldap.h> 37*7c478bd9Sstevel@tonic-gate #include "db_headers.h" 38*7c478bd9Sstevel@tonic-gate #include "db_table.h" 39*7c478bd9Sstevel@tonic-gate #include "db_pickle.h" /* for dump and load */ 40*7c478bd9Sstevel@tonic-gate #include "db_entry.h" 41*7c478bd9Sstevel@tonic-gate #include "nisdb_mt.h" 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate #include "ldap_parse.h" 44*7c478bd9Sstevel@tonic-gate #include "ldap_util.h" 45*7c478bd9Sstevel@tonic-gate #include "ldap_map.h" 46*7c478bd9Sstevel@tonic-gate #include "ldap_xdr.h" 47*7c478bd9Sstevel@tonic-gate #include "nis_hashitem.h" 48*7c478bd9Sstevel@tonic-gate #include "nisdb_ldap.h" 49*7c478bd9Sstevel@tonic-gate #include "nis_parse_ldap_conf.h" 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate static time_t maxTimeT; 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate /* 54*7c478bd9Sstevel@tonic-gate * Find the largest (positive) value of time_t. 55*7c478bd9Sstevel@tonic-gate * 56*7c478bd9Sstevel@tonic-gate * If time_t is unsigned, the largest possible value is just ~0. 57*7c478bd9Sstevel@tonic-gate * However, if it's signed, then ~0 is negative. Since lint (for 58*7c478bd9Sstevel@tonic-gate * sure), and perhaps the compiler too, dislike comparing an 59*7c478bd9Sstevel@tonic-gate * unsigned quantity to see if it's less than zero, we compare 60*7c478bd9Sstevel@tonic-gate * to one instead. If negative, the largest possible value is 61*7c478bd9Sstevel@tonic-gate * th inverse of 2**(N-1), where N is the number of bits in a 62*7c478bd9Sstevel@tonic-gate * time_t. 63*7c478bd9Sstevel@tonic-gate */ 64*7c478bd9Sstevel@tonic-gate extern "C" { 65*7c478bd9Sstevel@tonic-gate static void 66*7c478bd9Sstevel@tonic-gate __setMaxTimeT(void) 67*7c478bd9Sstevel@tonic-gate { 68*7c478bd9Sstevel@tonic-gate unsigned char b[sizeof (time_t)]; 69*7c478bd9Sstevel@tonic-gate int i; 70*7c478bd9Sstevel@tonic-gate 71*7c478bd9Sstevel@tonic-gate /* Compute ~0 for an unknown length integer */ 72*7c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (time_t); i++) { 73*7c478bd9Sstevel@tonic-gate b[i] = 0xff; 74*7c478bd9Sstevel@tonic-gate } 75*7c478bd9Sstevel@tonic-gate /* Set maxTimeT to ~0 of appropriate length */ 76*7c478bd9Sstevel@tonic-gate (void) memcpy(&maxTimeT, b, sizeof (time_t)); 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate if (maxTimeT < 1) 79*7c478bd9Sstevel@tonic-gate maxTimeT = ~(1<<((8*sizeof (maxTimeT))-1)); 80*7c478bd9Sstevel@tonic-gate } 81*7c478bd9Sstevel@tonic-gate #pragma init(__setMaxTimeT) 82*7c478bd9Sstevel@tonic-gate } 83*7c478bd9Sstevel@tonic-gate 84*7c478bd9Sstevel@tonic-gate /* How much to grow table by */ 85*7c478bd9Sstevel@tonic-gate #define DB_TABLE_GROWTH_INCREMENT 1024 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate /* 0'th not used; might be confusing. */ 88*7c478bd9Sstevel@tonic-gate #define DB_TABLE_START 1 89*7c478bd9Sstevel@tonic-gate 90*7c478bd9Sstevel@tonic-gate /* prevents wrap around numbers from being passed */ 91*7c478bd9Sstevel@tonic-gate #define CALLOC_LIMIT 536870911 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate /* Initial table sizes to use before using 1K increments. */ 94*7c478bd9Sstevel@tonic-gate /* This helps conserve memory usage when there are lots of small tables. */ 95*7c478bd9Sstevel@tonic-gate static int tabsizes[] = { 96*7c478bd9Sstevel@tonic-gate 16, 97*7c478bd9Sstevel@tonic-gate 128, 98*7c478bd9Sstevel@tonic-gate 512, 99*7c478bd9Sstevel@tonic-gate DB_TABLE_GROWTH_INCREMENT, 100*7c478bd9Sstevel@tonic-gate 0 101*7c478bd9Sstevel@tonic-gate }; 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate /* Returns the next size to use for table */ 104*7c478bd9Sstevel@tonic-gate static long unsigned 105*7c478bd9Sstevel@tonic-gate get_new_table_size(long unsigned oldsize) 106*7c478bd9Sstevel@tonic-gate { 107*7c478bd9Sstevel@tonic-gate long unsigned newsize = 0, n; 108*7c478bd9Sstevel@tonic-gate if (oldsize == 0) 109*7c478bd9Sstevel@tonic-gate newsize = tabsizes[0]; 110*7c478bd9Sstevel@tonic-gate else { 111*7c478bd9Sstevel@tonic-gate for (n = 0; newsize = tabsizes[n++]; ) 112*7c478bd9Sstevel@tonic-gate if (oldsize == newsize) { 113*7c478bd9Sstevel@tonic-gate newsize = tabsizes[n]; /* get next size */ 114*7c478bd9Sstevel@tonic-gate break; 115*7c478bd9Sstevel@tonic-gate } 116*7c478bd9Sstevel@tonic-gate if (newsize == 0) 117*7c478bd9Sstevel@tonic-gate newsize = oldsize + DB_TABLE_GROWTH_INCREMENT; 118*7c478bd9Sstevel@tonic-gate } 119*7c478bd9Sstevel@tonic-gate return (newsize); 120*7c478bd9Sstevel@tonic-gate } 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate /* destructor */ 124*7c478bd9Sstevel@tonic-gate db_free_list::~db_free_list() 125*7c478bd9Sstevel@tonic-gate { 126*7c478bd9Sstevel@tonic-gate WRITELOCKV(this, "w db_free_list::~db_free_list"); 127*7c478bd9Sstevel@tonic-gate reset(); /* free list entries */ 128*7c478bd9Sstevel@tonic-gate DESTROYRW(free_list); 129*7c478bd9Sstevel@tonic-gate } 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate void 132*7c478bd9Sstevel@tonic-gate db_free_list::reset() 133*7c478bd9Sstevel@tonic-gate { 134*7c478bd9Sstevel@tonic-gate db_free_entry *current, *nextentry; 135*7c478bd9Sstevel@tonic-gate 136*7c478bd9Sstevel@tonic-gate WRITELOCKV(this, "w db_free_list::reset"); 137*7c478bd9Sstevel@tonic-gate for (current = head; current != NULL; ) { 138*7c478bd9Sstevel@tonic-gate nextentry = current->next; 139*7c478bd9Sstevel@tonic-gate delete current; 140*7c478bd9Sstevel@tonic-gate current = nextentry; 141*7c478bd9Sstevel@tonic-gate } 142*7c478bd9Sstevel@tonic-gate head = NULL; 143*7c478bd9Sstevel@tonic-gate count = 0; 144*7c478bd9Sstevel@tonic-gate WRITEUNLOCKV(this, "wu db_free_list::reset"); 145*7c478bd9Sstevel@tonic-gate } 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate /* Returns the location of a free entry, or NULL, if there aren't any. */ 148*7c478bd9Sstevel@tonic-gate entryp 149*7c478bd9Sstevel@tonic-gate db_free_list::pop() 150*7c478bd9Sstevel@tonic-gate { 151*7c478bd9Sstevel@tonic-gate WRITELOCK(this, NULL, "w db_free_list::pop"); 152*7c478bd9Sstevel@tonic-gate if (head == NULL) { 153*7c478bd9Sstevel@tonic-gate WRITEUNLOCK(this, NULL, "wu db_free_list::pop"); 154*7c478bd9Sstevel@tonic-gate return (NULL); 155*7c478bd9Sstevel@tonic-gate } 156*7c478bd9Sstevel@tonic-gate db_free_entry* old_head = head; 157*7c478bd9Sstevel@tonic-gate entryp found = head->where; 158*7c478bd9Sstevel@tonic-gate head = head->next; 159*7c478bd9Sstevel@tonic-gate delete old_head; 160*7c478bd9Sstevel@tonic-gate --count; 161*7c478bd9Sstevel@tonic-gate WRITEUNLOCK(this, found, "wu db_free_list::pop"); 162*7c478bd9Sstevel@tonic-gate return (found); 163*7c478bd9Sstevel@tonic-gate } 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate /* 166*7c478bd9Sstevel@tonic-gate * Adds given location to the free list. 167*7c478bd9Sstevel@tonic-gate * Returns TRUE if successful, FALSE otherwise (when out of memory). 168*7c478bd9Sstevel@tonic-gate */ 169*7c478bd9Sstevel@tonic-gate bool_t 170*7c478bd9Sstevel@tonic-gate db_free_list::push(entryp tabloc) 171*7c478bd9Sstevel@tonic-gate { 172*7c478bd9Sstevel@tonic-gate db_free_entry * newentry = new db_free_entry; 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate WRITELOCK(this, FALSE, "w db_free_list::push"); 175*7c478bd9Sstevel@tonic-gate if (newentry == NULL) { 176*7c478bd9Sstevel@tonic-gate WRITEUNLOCK(this, FALSE, "wu db_free_list::push"); 177*7c478bd9Sstevel@tonic-gate FATAL3("db_free_list::push: cannot allocation space", 178*7c478bd9Sstevel@tonic-gate DB_MEMORY_LIMIT, FALSE); 179*7c478bd9Sstevel@tonic-gate } 180*7c478bd9Sstevel@tonic-gate newentry->where = tabloc; 181*7c478bd9Sstevel@tonic-gate newentry->next = head; 182*7c478bd9Sstevel@tonic-gate head = newentry; 183*7c478bd9Sstevel@tonic-gate ++count; 184*7c478bd9Sstevel@tonic-gate WRITEUNLOCK(this, TRUE, "wu db_free_list::push"); 185*7c478bd9Sstevel@tonic-gate return (TRUE); 186*7c478bd9Sstevel@tonic-gate } 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate /* 189*7c478bd9Sstevel@tonic-gate * Returns in a vector the information in the free list. 190*7c478bd9Sstevel@tonic-gate * Vector returned is of form: [n free cells][n1][n2][loc1], ..[locn]. 191*7c478bd9Sstevel@tonic-gate * Leave the first 'n' cells free. 192*7c478bd9Sstevel@tonic-gate * n1 is the number of entries that should be in the freelist. 193*7c478bd9Sstevel@tonic-gate * n2 is the number of entries actually found in the freelist. 194*7c478bd9Sstevel@tonic-gate * [loc1...locn] are the entries. n2 <= n1 because we never count beyond n1. 195*7c478bd9Sstevel@tonic-gate * It is up to the caller to free the returned vector when he is through. 196*7c478bd9Sstevel@tonic-gate */ 197*7c478bd9Sstevel@tonic-gate long * 198*7c478bd9Sstevel@tonic-gate db_free_list::stats(int nslots) 199*7c478bd9Sstevel@tonic-gate { 200*7c478bd9Sstevel@tonic-gate long realcount = 0, 201*7c478bd9Sstevel@tonic-gate i, 202*7c478bd9Sstevel@tonic-gate liststart = nslots, // start of freelist 203*7c478bd9Sstevel@tonic-gate listend = nslots+count+2; // end of freelist 204*7c478bd9Sstevel@tonic-gate db_free_entry_p current = head; 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate READLOCK(this, NULL, "r db_free_list::stats"); 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate long *answer = (long *)malloc((int)(listend)*sizeof (long)); 209*7c478bd9Sstevel@tonic-gate if (answer == 0) { 210*7c478bd9Sstevel@tonic-gate READUNLOCK(this, NULL, "ru db_free_list::stats"); 211*7c478bd9Sstevel@tonic-gate FATAL3("db_free_list::stats: cannot allocation space", 212*7c478bd9Sstevel@tonic-gate DB_MEMORY_LIMIT, NULL); 213*7c478bd9Sstevel@tonic-gate } 214*7c478bd9Sstevel@tonic-gate 215*7c478bd9Sstevel@tonic-gate answer[liststart] = count; /* size of freelist */ 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate for (i = liststart+2; i < listend && current != NULL; i++) { 218*7c478bd9Sstevel@tonic-gate answer[i] = current->where; 219*7c478bd9Sstevel@tonic-gate current = current->next; 220*7c478bd9Sstevel@tonic-gate ++realcount; 221*7c478bd9Sstevel@tonic-gate } 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate answer[liststart+1] = realcount; 224*7c478bd9Sstevel@tonic-gate READUNLOCK(this, answer, "ru db_free_list::stats"); 225*7c478bd9Sstevel@tonic-gate return (answer); 226*7c478bd9Sstevel@tonic-gate } 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate /* Set default values for the mapping structure */ 230*7c478bd9Sstevel@tonic-gate void 231*7c478bd9Sstevel@tonic-gate db_table::initMappingStruct(__nisdb_table_mapping_t *m) { 232*7c478bd9Sstevel@tonic-gate if (m == 0) 233*7c478bd9Sstevel@tonic-gate return; 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate m->initTtlLo = (ldapDBTableMapping.initTtlLo > 0) ? 236*7c478bd9Sstevel@tonic-gate ldapDBTableMapping.initTtlLo : (3600-1800); 237*7c478bd9Sstevel@tonic-gate m->initTtlHi = (ldapDBTableMapping.initTtlHi > 0) ? 238*7c478bd9Sstevel@tonic-gate ldapDBTableMapping.initTtlHi : (3600+1800); 239*7c478bd9Sstevel@tonic-gate m->ttl = (ldapDBTableMapping.ttl > 0) ? 240*7c478bd9Sstevel@tonic-gate ldapDBTableMapping.ttl : 3600; 241*7c478bd9Sstevel@tonic-gate m->enumExpire = 0; 242*7c478bd9Sstevel@tonic-gate m->fromLDAP = FALSE; 243*7c478bd9Sstevel@tonic-gate m->toLDAP = FALSE; 244*7c478bd9Sstevel@tonic-gate m->isMaster = FALSE; 245*7c478bd9Sstevel@tonic-gate m->retrieveError = ldapDBTableMapping.retrieveError; 246*7c478bd9Sstevel@tonic-gate m->retrieveErrorRetry.attempts = 247*7c478bd9Sstevel@tonic-gate ldapDBTableMapping.retrieveErrorRetry.attempts; 248*7c478bd9Sstevel@tonic-gate m->retrieveErrorRetry.timeout = 249*7c478bd9Sstevel@tonic-gate ldapDBTableMapping.retrieveErrorRetry.timeout; 250*7c478bd9Sstevel@tonic-gate m->storeError = ldapDBTableMapping.storeError; 251*7c478bd9Sstevel@tonic-gate m->storeErrorRetry.attempts = 252*7c478bd9Sstevel@tonic-gate ldapDBTableMapping.storeErrorRetry.attempts; 253*7c478bd9Sstevel@tonic-gate m->storeErrorRetry.timeout = 254*7c478bd9Sstevel@tonic-gate ldapDBTableMapping.storeErrorRetry.timeout; 255*7c478bd9Sstevel@tonic-gate m->storeErrorDisp = ldapDBTableMapping.storeErrorDisp; 256*7c478bd9Sstevel@tonic-gate m->refreshError = ldapDBTableMapping.refreshError; 257*7c478bd9Sstevel@tonic-gate m->refreshErrorRetry.attempts = 258*7c478bd9Sstevel@tonic-gate ldapDBTableMapping.refreshErrorRetry.attempts; 259*7c478bd9Sstevel@tonic-gate m->refreshErrorRetry.timeout = 260*7c478bd9Sstevel@tonic-gate ldapDBTableMapping.refreshErrorRetry.timeout; 261*7c478bd9Sstevel@tonic-gate m->matchFetch = ldapDBTableMapping.matchFetch; 262*7c478bd9Sstevel@tonic-gate 263*7c478bd9Sstevel@tonic-gate if (mapping.expire != 0) 264*7c478bd9Sstevel@tonic-gate free(mapping.expire); 265*7c478bd9Sstevel@tonic-gate m->expire = 0; 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate if (m->tm != 0) 268*7c478bd9Sstevel@tonic-gate free(m->tm); 269*7c478bd9Sstevel@tonic-gate m->tm = 0; 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate /* 272*7c478bd9Sstevel@tonic-gate * The 'objType' field obviously indicates the type of object. 273*7c478bd9Sstevel@tonic-gate * However, we also use it to tell us if we've retrieved mapping 274*7c478bd9Sstevel@tonic-gate * data from LDAP or not; in the latter case, 'objType' is 275*7c478bd9Sstevel@tonic-gate * NIS_BOGUS_OBJ. For purposes of maintaining expiration times, 276*7c478bd9Sstevel@tonic-gate * we may need to know if the object is a table or a directory 277*7c478bd9Sstevel@tonic-gate * _before_ we've retrieved any mapping data. Hence the 'expireType' 278*7c478bd9Sstevel@tonic-gate * field, which starts as NIS_BOGUS_OBJ (meaning, don't know, assume 279*7c478bd9Sstevel@tonic-gate * directory for now), and later is set to NIS_DIRECTORY_OBJ 280*7c478bd9Sstevel@tonic-gate * (always keep expiration data, in case one of the dir entries 281*7c478bd9Sstevel@tonic-gate * is mapped) or NIS_TABLE_OBJ (only need expiration data if 282*7c478bd9Sstevel@tonic-gate * tha table is mapped). 283*7c478bd9Sstevel@tonic-gate */ 284*7c478bd9Sstevel@tonic-gate m->objType = NIS_BOGUS_OBJ; 285*7c478bd9Sstevel@tonic-gate m->expireType = NIS_BOGUS_OBJ; 286*7c478bd9Sstevel@tonic-gate if (m->objName != 0) 287*7c478bd9Sstevel@tonic-gate free(m->objName); 288*7c478bd9Sstevel@tonic-gate m->objName = 0; 289*7c478bd9Sstevel@tonic-gate } 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate void 292*7c478bd9Sstevel@tonic-gate db_table::db_table_ldap_init(void) { 293*7c478bd9Sstevel@tonic-gate 294*7c478bd9Sstevel@tonic-gate INITRW(table); 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate enumMode.flag = 0; 297*7c478bd9Sstevel@tonic-gate enumCount.flag = 0; 298*7c478bd9Sstevel@tonic-gate enumIndex.ptr = 0; 299*7c478bd9Sstevel@tonic-gate enumArray.ptr = 0; 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate mapping.expire = 0; 302*7c478bd9Sstevel@tonic-gate mapping.tm = 0; 303*7c478bd9Sstevel@tonic-gate mapping.objName = 0; 304*7c478bd9Sstevel@tonic-gate mapping.isDeferredTable = FALSE; 305*7c478bd9Sstevel@tonic-gate (void) mutex_init(&mapping.enumLock, 0, 0); 306*7c478bd9Sstevel@tonic-gate mapping.enumTid = 0; 307*7c478bd9Sstevel@tonic-gate mapping.enumStat = -1; 308*7c478bd9Sstevel@tonic-gate mapping.enumDeferred = 0; 309*7c478bd9Sstevel@tonic-gate mapping.enumEntries = 0; 310*7c478bd9Sstevel@tonic-gate mapping.enumTime = 0; 311*7c478bd9Sstevel@tonic-gate } 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate /* db_table constructor */ 314*7c478bd9Sstevel@tonic-gate db_table::db_table() : freelist() 315*7c478bd9Sstevel@tonic-gate { 316*7c478bd9Sstevel@tonic-gate tab = NULL; 317*7c478bd9Sstevel@tonic-gate table_size = 0; 318*7c478bd9Sstevel@tonic-gate last_used = 0; 319*7c478bd9Sstevel@tonic-gate count = 0; 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate db_table_ldap_init(); 322*7c478bd9Sstevel@tonic-gate initMappingStruct(&mapping); 323*7c478bd9Sstevel@tonic-gate 324*7c478bd9Sstevel@tonic-gate /* grow(); */ 325*7c478bd9Sstevel@tonic-gate } 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate /* 328*7c478bd9Sstevel@tonic-gate * db_table destructor: 329*7c478bd9Sstevel@tonic-gate * 1. Get rid of contents of freelist 330*7c478bd9Sstevel@tonic-gate * 2. delete all entries hanging off table 331*7c478bd9Sstevel@tonic-gate * 3. get rid of table itself 332*7c478bd9Sstevel@tonic-gate */ 333*7c478bd9Sstevel@tonic-gate db_table::~db_table() 334*7c478bd9Sstevel@tonic-gate { 335*7c478bd9Sstevel@tonic-gate WRITELOCKV(this, "w db_table::~db_table"); 336*7c478bd9Sstevel@tonic-gate reset(); 337*7c478bd9Sstevel@tonic-gate DESTROYRW(table); 338*7c478bd9Sstevel@tonic-gate } 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate /* reset size and pointers */ 341*7c478bd9Sstevel@tonic-gate void 342*7c478bd9Sstevel@tonic-gate db_table::reset() 343*7c478bd9Sstevel@tonic-gate { 344*7c478bd9Sstevel@tonic-gate int i, done = 0; 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate WRITELOCKV(this, "w db_table::reset"); 347*7c478bd9Sstevel@tonic-gate freelist.reset(); 348*7c478bd9Sstevel@tonic-gate 349*7c478bd9Sstevel@tonic-gate /* Add sanity check in case of table corruption */ 350*7c478bd9Sstevel@tonic-gate if (tab != NULL) { 351*7c478bd9Sstevel@tonic-gate for (i = 0; 352*7c478bd9Sstevel@tonic-gate i <= last_used && i < table_size && done < count; 353*7c478bd9Sstevel@tonic-gate i++) { 354*7c478bd9Sstevel@tonic-gate if (tab[i]) { 355*7c478bd9Sstevel@tonic-gate free_entry(tab[i]); 356*7c478bd9Sstevel@tonic-gate ++done; 357*7c478bd9Sstevel@tonic-gate } 358*7c478bd9Sstevel@tonic-gate } 359*7c478bd9Sstevel@tonic-gate } 360*7c478bd9Sstevel@tonic-gate 361*7c478bd9Sstevel@tonic-gate delete tab; 362*7c478bd9Sstevel@tonic-gate table_size = last_used = count = 0; 363*7c478bd9Sstevel@tonic-gate tab = NULL; 364*7c478bd9Sstevel@tonic-gate sfree(mapping.expire); 365*7c478bd9Sstevel@tonic-gate mapping.expire = NULL; 366*7c478bd9Sstevel@tonic-gate mapping.objType = NIS_BOGUS_OBJ; 367*7c478bd9Sstevel@tonic-gate mapping.expireType = NIS_BOGUS_OBJ; 368*7c478bd9Sstevel@tonic-gate sfree(mapping.objName); 369*7c478bd9Sstevel@tonic-gate mapping.objName = 0; 370*7c478bd9Sstevel@tonic-gate /* Leave other values of the mapping structure unchanged */ 371*7c478bd9Sstevel@tonic-gate enumMode.flag = 0; 372*7c478bd9Sstevel@tonic-gate enumCount.flag = 0; 373*7c478bd9Sstevel@tonic-gate sfree(enumIndex.ptr); 374*7c478bd9Sstevel@tonic-gate enumIndex.ptr = 0; 375*7c478bd9Sstevel@tonic-gate sfree(enumArray.ptr); 376*7c478bd9Sstevel@tonic-gate enumArray.ptr = 0; 377*7c478bd9Sstevel@tonic-gate WRITEUNLOCKV(this, "wu db_table::reset"); 378*7c478bd9Sstevel@tonic-gate } 379*7c478bd9Sstevel@tonic-gate 380*7c478bd9Sstevel@tonic-gate db_status 381*7c478bd9Sstevel@tonic-gate db_table::allocateExpire(long oldSize, long newSize) { 382*7c478bd9Sstevel@tonic-gate time_t *newExpire; 383*7c478bd9Sstevel@tonic-gate 384*7c478bd9Sstevel@tonic-gate newExpire = (time_t *)realloc(mapping.expire, 385*7c478bd9Sstevel@tonic-gate newSize * sizeof (mapping.expire[0])); 386*7c478bd9Sstevel@tonic-gate if (newExpire != NULL) { 387*7c478bd9Sstevel@tonic-gate /* Initialize new portion */ 388*7c478bd9Sstevel@tonic-gate (void) memset(&newExpire[oldSize], 0, 389*7c478bd9Sstevel@tonic-gate (newSize-oldSize) * sizeof (newExpire[0])); 390*7c478bd9Sstevel@tonic-gate mapping.expire = newExpire; 391*7c478bd9Sstevel@tonic-gate } else { 392*7c478bd9Sstevel@tonic-gate return (DB_MEMORY_LIMIT); 393*7c478bd9Sstevel@tonic-gate } 394*7c478bd9Sstevel@tonic-gate 395*7c478bd9Sstevel@tonic-gate return (DB_SUCCESS); 396*7c478bd9Sstevel@tonic-gate } 397*7c478bd9Sstevel@tonic-gate 398*7c478bd9Sstevel@tonic-gate db_status 399*7c478bd9Sstevel@tonic-gate db_table::allocateEnumArray(long oldSize, long newSize) { 400*7c478bd9Sstevel@tonic-gate entry_object **newEnumArray; 401*7c478bd9Sstevel@tonic-gate char *myself = "db_table::allocateEnumArray"; 402*7c478bd9Sstevel@tonic-gate 403*7c478bd9Sstevel@tonic-gate if (enumCount.flag > 0) { 404*7c478bd9Sstevel@tonic-gate if (enumIndex.ptr == 0) { 405*7c478bd9Sstevel@tonic-gate enumIndex.ptr = (entryp *)am(myself, enumCount.flag * 406*7c478bd9Sstevel@tonic-gate sizeof (entryp)); 407*7c478bd9Sstevel@tonic-gate if (enumIndex.ptr == 0) 408*7c478bd9Sstevel@tonic-gate return (DB_MEMORY_LIMIT); 409*7c478bd9Sstevel@tonic-gate } 410*7c478bd9Sstevel@tonic-gate oldSize = 0; 411*7c478bd9Sstevel@tonic-gate newSize = enumCount.flag; 412*7c478bd9Sstevel@tonic-gate } 413*7c478bd9Sstevel@tonic-gate newEnumArray = (entry_object **)realloc(enumArray.ptr, 414*7c478bd9Sstevel@tonic-gate newSize * sizeof (entry_object *)); 415*7c478bd9Sstevel@tonic-gate if (newEnumArray != 0 && newSize > oldSize) { 416*7c478bd9Sstevel@tonic-gate (void) memcpy(&newEnumArray[oldSize], &tab[oldSize], 417*7c478bd9Sstevel@tonic-gate (newSize-oldSize) * sizeof (entry_object *)); 418*7c478bd9Sstevel@tonic-gate enumArray.ptr = newEnumArray; 419*7c478bd9Sstevel@tonic-gate } else if (newEnumArray == 0) { 420*7c478bd9Sstevel@tonic-gate return (DB_MEMORY_LIMIT); 421*7c478bd9Sstevel@tonic-gate } 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate return (DB_SUCCESS); 424*7c478bd9Sstevel@tonic-gate } 425*7c478bd9Sstevel@tonic-gate 426*7c478bd9Sstevel@tonic-gate /* Expand the table. Fatal error if insufficient memory. */ 427*7c478bd9Sstevel@tonic-gate void 428*7c478bd9Sstevel@tonic-gate db_table::grow() 429*7c478bd9Sstevel@tonic-gate { 430*7c478bd9Sstevel@tonic-gate WRITELOCKV(this, "w db_table::grow"); 431*7c478bd9Sstevel@tonic-gate long oldsize = table_size; 432*7c478bd9Sstevel@tonic-gate entry_object_p *oldtab = tab; 433*7c478bd9Sstevel@tonic-gate long i; 434*7c478bd9Sstevel@tonic-gate 435*7c478bd9Sstevel@tonic-gate table_size = get_new_table_size(oldsize); 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 438*7c478bd9Sstevel@tonic-gate fprintf(stderr, "db_table GROWING to %d\n", table_size); 439*7c478bd9Sstevel@tonic-gate #endif 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate if (table_size > CALLOC_LIMIT) { 442*7c478bd9Sstevel@tonic-gate table_size = oldsize; 443*7c478bd9Sstevel@tonic-gate WRITEUNLOCKV(this, "wu db_table::grow"); 444*7c478bd9Sstevel@tonic-gate FATAL("db_table::grow: table size exceeds calloc limit", 445*7c478bd9Sstevel@tonic-gate DB_MEMORY_LIMIT); 446*7c478bd9Sstevel@tonic-gate } 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate // if ((tab = new entry_object_p[table_size]) == NULL) 449*7c478bd9Sstevel@tonic-gate if ((tab = (entry_object_p*) 450*7c478bd9Sstevel@tonic-gate calloc((unsigned int) table_size, 451*7c478bd9Sstevel@tonic-gate sizeof (entry_object_p))) == NULL) { 452*7c478bd9Sstevel@tonic-gate tab = oldtab; // restore previous table info 453*7c478bd9Sstevel@tonic-gate table_size = oldsize; 454*7c478bd9Sstevel@tonic-gate WRITEUNLOCKV(this, "wu db_table::grow"); 455*7c478bd9Sstevel@tonic-gate FATAL("db_table::grow: cannot allocate space", DB_MEMORY_LIMIT); 456*7c478bd9Sstevel@tonic-gate } 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate /* 459*7c478bd9Sstevel@tonic-gate * For directories, we may need the expire time array even if the 460*7c478bd9Sstevel@tonic-gate * directory itself isn't mapped. If the objType and expireType both 461*7c478bd9Sstevel@tonic-gate * are bogus, we don't know yet if this is a table or a directory, 462*7c478bd9Sstevel@tonic-gate * and must proceed accordingly. 463*7c478bd9Sstevel@tonic-gate */ 464*7c478bd9Sstevel@tonic-gate if (mapping.objType == NIS_DIRECTORY_OBJ || 465*7c478bd9Sstevel@tonic-gate mapping.expireType != NIS_TABLE_OBJ || 466*7c478bd9Sstevel@tonic-gate mapping.fromLDAP) { 467*7c478bd9Sstevel@tonic-gate db_status stat = allocateExpire(oldsize, table_size); 468*7c478bd9Sstevel@tonic-gate if (stat != DB_SUCCESS) { 469*7c478bd9Sstevel@tonic-gate free(tab); 470*7c478bd9Sstevel@tonic-gate tab = oldtab; 471*7c478bd9Sstevel@tonic-gate table_size = oldsize; 472*7c478bd9Sstevel@tonic-gate WRITEUNLOCKV(this, "wu db_table::grow expire"); 473*7c478bd9Sstevel@tonic-gate FATAL( 474*7c478bd9Sstevel@tonic-gate "db_table::grow: cannot allocate space for expire", stat); 475*7c478bd9Sstevel@tonic-gate } 476*7c478bd9Sstevel@tonic-gate } 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate if (oldtab != NULL) { 479*7c478bd9Sstevel@tonic-gate for (i = 0; i < oldsize; i++) { // transfer old to new 480*7c478bd9Sstevel@tonic-gate tab[i] = oldtab[i]; 481*7c478bd9Sstevel@tonic-gate } 482*7c478bd9Sstevel@tonic-gate delete oldtab; 483*7c478bd9Sstevel@tonic-gate } 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate if (enumMode.flag) { 486*7c478bd9Sstevel@tonic-gate db_status stat = allocateEnumArray(oldsize, table_size); 487*7c478bd9Sstevel@tonic-gate if (stat != DB_SUCCESS) { 488*7c478bd9Sstevel@tonic-gate free(tab); 489*7c478bd9Sstevel@tonic-gate tab = oldtab; 490*7c478bd9Sstevel@tonic-gate table_size = oldsize; 491*7c478bd9Sstevel@tonic-gate WRITEUNLOCKV(this, "wu db_table::grow enumArray"); 492*7c478bd9Sstevel@tonic-gate FATAL( 493*7c478bd9Sstevel@tonic-gate "db_table::grow: cannot allocate space for enumArray", stat); 494*7c478bd9Sstevel@tonic-gate } 495*7c478bd9Sstevel@tonic-gate } 496*7c478bd9Sstevel@tonic-gate 497*7c478bd9Sstevel@tonic-gate WRITEUNLOCKV(this, "wu db_table::grow"); 498*7c478bd9Sstevel@tonic-gate } 499*7c478bd9Sstevel@tonic-gate 500*7c478bd9Sstevel@tonic-gate /* 501*7c478bd9Sstevel@tonic-gate * Return the first entry in table, also return its position in 502*7c478bd9Sstevel@tonic-gate * 'where'. Return NULL in both if no next entry is found. 503*7c478bd9Sstevel@tonic-gate */ 504*7c478bd9Sstevel@tonic-gate entry_object* 505*7c478bd9Sstevel@tonic-gate db_table::first_entry(entryp * where) 506*7c478bd9Sstevel@tonic-gate { 507*7c478bd9Sstevel@tonic-gate ASSERTRHELD(table); 508*7c478bd9Sstevel@tonic-gate if (count == 0 || tab == NULL) { /* empty table */ 509*7c478bd9Sstevel@tonic-gate *where = NULL; 510*7c478bd9Sstevel@tonic-gate return (NULL); 511*7c478bd9Sstevel@tonic-gate } else { 512*7c478bd9Sstevel@tonic-gate entryp i; 513*7c478bd9Sstevel@tonic-gate for (i = DB_TABLE_START; 514*7c478bd9Sstevel@tonic-gate i < table_size && i <= last_used; i++) { 515*7c478bd9Sstevel@tonic-gate if (tab[i] != NULL) { 516*7c478bd9Sstevel@tonic-gate *where = i; 517*7c478bd9Sstevel@tonic-gate return (tab[i]); 518*7c478bd9Sstevel@tonic-gate } 519*7c478bd9Sstevel@tonic-gate } 520*7c478bd9Sstevel@tonic-gate } 521*7c478bd9Sstevel@tonic-gate *where = NULL; 522*7c478bd9Sstevel@tonic-gate return (NULL); 523*7c478bd9Sstevel@tonic-gate } 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate /* 526*7c478bd9Sstevel@tonic-gate * Return the next entry in table from 'prev', also return its position in 527*7c478bd9Sstevel@tonic-gate * 'newentry'. Return NULL in both if no next entry is found. 528*7c478bd9Sstevel@tonic-gate */ 529*7c478bd9Sstevel@tonic-gate entry_object * 530*7c478bd9Sstevel@tonic-gate db_table::next_entry(entryp prev, entryp* newentry) 531*7c478bd9Sstevel@tonic-gate { 532*7c478bd9Sstevel@tonic-gate long i; 533*7c478bd9Sstevel@tonic-gate 534*7c478bd9Sstevel@tonic-gate ASSERTRHELD(table); 535*7c478bd9Sstevel@tonic-gate if (prev >= table_size || tab == NULL || tab[prev] == NULL) 536*7c478bd9Sstevel@tonic-gate return (NULL); 537*7c478bd9Sstevel@tonic-gate for (i = prev+1; i < table_size && i <= last_used; i++) { 538*7c478bd9Sstevel@tonic-gate if (tab[i] != NULL) { 539*7c478bd9Sstevel@tonic-gate *newentry = i; 540*7c478bd9Sstevel@tonic-gate return (tab[i]); 541*7c478bd9Sstevel@tonic-gate } 542*7c478bd9Sstevel@tonic-gate } 543*7c478bd9Sstevel@tonic-gate *newentry = NULL; 544*7c478bd9Sstevel@tonic-gate return (NULL); 545*7c478bd9Sstevel@tonic-gate } 546*7c478bd9Sstevel@tonic-gate 547*7c478bd9Sstevel@tonic-gate /* Return entry at location 'where', NULL if location is invalid. */ 548*7c478bd9Sstevel@tonic-gate entry_object * 549*7c478bd9Sstevel@tonic-gate db_table::get_entry(entryp where) 550*7c478bd9Sstevel@tonic-gate { 551*7c478bd9Sstevel@tonic-gate ASSERTRHELD(table); 552*7c478bd9Sstevel@tonic-gate if (where < table_size && tab != NULL && tab[where] != NULL) 553*7c478bd9Sstevel@tonic-gate return (tab[where]); 554*7c478bd9Sstevel@tonic-gate else 555*7c478bd9Sstevel@tonic-gate return (NULL); 556*7c478bd9Sstevel@tonic-gate } 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate void 559*7c478bd9Sstevel@tonic-gate db_table::setEntryExp(entryp where, entry_obj *obj, int initialLoad) { 560*7c478bd9Sstevel@tonic-gate nis_object *o; 561*7c478bd9Sstevel@tonic-gate char *myself = "db_table::setEntryExp"; 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate /* 564*7c478bd9Sstevel@tonic-gate * If we don't know what type of object this is yet, we 565*7c478bd9Sstevel@tonic-gate * can find out now. If it's a directory, the pseudo-object 566*7c478bd9Sstevel@tonic-gate * in column zero will have the type "IN_DIRECTORY"; 567*7c478bd9Sstevel@tonic-gate * otherwise, it's a table object. 568*7c478bd9Sstevel@tonic-gate */ 569*7c478bd9Sstevel@tonic-gate if (mapping.expireType == NIS_BOGUS_OBJ) { 570*7c478bd9Sstevel@tonic-gate if (obj != 0) { 571*7c478bd9Sstevel@tonic-gate if (obj->en_type != 0 && 572*7c478bd9Sstevel@tonic-gate strcmp(obj->en_type, "IN_DIRECTORY") == 0) { 573*7c478bd9Sstevel@tonic-gate mapping.expireType = NIS_DIRECTORY_OBJ; 574*7c478bd9Sstevel@tonic-gate } else { 575*7c478bd9Sstevel@tonic-gate mapping.expireType = NIS_TABLE_OBJ; 576*7c478bd9Sstevel@tonic-gate if (!mapping.fromLDAP) { 577*7c478bd9Sstevel@tonic-gate free(mapping.expire); 578*7c478bd9Sstevel@tonic-gate mapping.expire = 0; 579*7c478bd9Sstevel@tonic-gate } 580*7c478bd9Sstevel@tonic-gate } 581*7c478bd9Sstevel@tonic-gate } 582*7c478bd9Sstevel@tonic-gate } 583*7c478bd9Sstevel@tonic-gate 584*7c478bd9Sstevel@tonic-gate /* Set the entry TTL */ 585*7c478bd9Sstevel@tonic-gate if (mapping.expire != NULL) { 586*7c478bd9Sstevel@tonic-gate struct timeval now; 587*7c478bd9Sstevel@tonic-gate time_t lo, hi, ttl; 588*7c478bd9Sstevel@tonic-gate 589*7c478bd9Sstevel@tonic-gate (void) gettimeofday(&now, NULL); 590*7c478bd9Sstevel@tonic-gate if (mapping.expireType == NIS_TABLE_OBJ) { 591*7c478bd9Sstevel@tonic-gate lo = mapping.initTtlLo; 592*7c478bd9Sstevel@tonic-gate hi = mapping.initTtlHi; 593*7c478bd9Sstevel@tonic-gate ttl = mapping.ttl; 594*7c478bd9Sstevel@tonic-gate /* TTL == 0 means always expired */ 595*7c478bd9Sstevel@tonic-gate if (ttl == 0) 596*7c478bd9Sstevel@tonic-gate ttl = -1; 597*7c478bd9Sstevel@tonic-gate } else { 598*7c478bd9Sstevel@tonic-gate __nis_table_mapping_t *t = 0; 599*7c478bd9Sstevel@tonic-gate 600*7c478bd9Sstevel@tonic-gate o = unmakePseudoEntryObj(obj, 0); 601*7c478bd9Sstevel@tonic-gate if (o != 0) { 602*7c478bd9Sstevel@tonic-gate __nis_buffer_t b = {0, 0}; 603*7c478bd9Sstevel@tonic-gate 604*7c478bd9Sstevel@tonic-gate bp2buf(myself, &b, "%s.%s", 605*7c478bd9Sstevel@tonic-gate o->zo_name, o->zo_domain); 606*7c478bd9Sstevel@tonic-gate t = getObjMapping(b.buf, 0, 1, 0, 0); 607*7c478bd9Sstevel@tonic-gate sfree(b.buf); 608*7c478bd9Sstevel@tonic-gate nis_destroy_object(o); 609*7c478bd9Sstevel@tonic-gate } 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate if (t != 0) { 612*7c478bd9Sstevel@tonic-gate lo = t->initTtlLo; 613*7c478bd9Sstevel@tonic-gate hi = t->initTtlHi; 614*7c478bd9Sstevel@tonic-gate ttl = t->ttl; 615*7c478bd9Sstevel@tonic-gate /* TTL == 0 means always expired */ 616*7c478bd9Sstevel@tonic-gate if (ttl == 0) 617*7c478bd9Sstevel@tonic-gate ttl = -1; 618*7c478bd9Sstevel@tonic-gate } else { 619*7c478bd9Sstevel@tonic-gate /* 620*7c478bd9Sstevel@tonic-gate * No expiration time initialization 621*7c478bd9Sstevel@tonic-gate * data. Cook up values that will 622*7c478bd9Sstevel@tonic-gate * result in mapping.expire[where] 623*7c478bd9Sstevel@tonic-gate * set to maxTimeT. 624*7c478bd9Sstevel@tonic-gate */ 625*7c478bd9Sstevel@tonic-gate hi = lo = ttl = maxTimeT - now.tv_sec; 626*7c478bd9Sstevel@tonic-gate } 627*7c478bd9Sstevel@tonic-gate } 628*7c478bd9Sstevel@tonic-gate 629*7c478bd9Sstevel@tonic-gate if (initialLoad) { 630*7c478bd9Sstevel@tonic-gate int interval = hi - lo + 1; 631*7c478bd9Sstevel@tonic-gate if (interval <= 1) { 632*7c478bd9Sstevel@tonic-gate mapping.expire[where] = now.tv_sec + lo; 633*7c478bd9Sstevel@tonic-gate } else { 634*7c478bd9Sstevel@tonic-gate srand48(now.tv_sec); 635*7c478bd9Sstevel@tonic-gate mapping.expire[where] = now.tv_sec + 636*7c478bd9Sstevel@tonic-gate (lrand48() % interval); 637*7c478bd9Sstevel@tonic-gate } 638*7c478bd9Sstevel@tonic-gate if (mapping.enumExpire == 0 || 639*7c478bd9Sstevel@tonic-gate mapping.expire[where] < 640*7c478bd9Sstevel@tonic-gate mapping.enumExpire) 641*7c478bd9Sstevel@tonic-gate mapping.enumExpire = mapping.expire[where]; 642*7c478bd9Sstevel@tonic-gate } else { 643*7c478bd9Sstevel@tonic-gate mapping.expire[where] = now.tv_sec + ttl; 644*7c478bd9Sstevel@tonic-gate } 645*7c478bd9Sstevel@tonic-gate } 646*7c478bd9Sstevel@tonic-gate } 647*7c478bd9Sstevel@tonic-gate 648*7c478bd9Sstevel@tonic-gate /* 649*7c478bd9Sstevel@tonic-gate * Add given entry to table in first available slot (either look in freelist 650*7c478bd9Sstevel@tonic-gate * or add to end of table) and return the the position of where the record 651*7c478bd9Sstevel@tonic-gate * is placed. 'count' is incremented if entry is added. Table may grow 652*7c478bd9Sstevel@tonic-gate * as a side-effect of the addition. Copy is made of input. 653*7c478bd9Sstevel@tonic-gate */ 654*7c478bd9Sstevel@tonic-gate entryp 655*7c478bd9Sstevel@tonic-gate db_table::add_entry(entry_object *obj, int initialLoad) { 656*7c478bd9Sstevel@tonic-gate /* 657*7c478bd9Sstevel@tonic-gate * We're returning an index of the table array, so the caller 658*7c478bd9Sstevel@tonic-gate * should hold a lock until done with the index. To save us 659*7c478bd9Sstevel@tonic-gate * the bother of upgrading to a write lock, it might as well 660*7c478bd9Sstevel@tonic-gate * be a write lock to begin with. 661*7c478bd9Sstevel@tonic-gate */ 662*7c478bd9Sstevel@tonic-gate ASSERTWHELD(table); 663*7c478bd9Sstevel@tonic-gate entryp where = freelist.pop(); 664*7c478bd9Sstevel@tonic-gate if (where == NULL) { /* empty freelist */ 665*7c478bd9Sstevel@tonic-gate if (last_used >= (table_size-1)) /* full (> is for 0) */ 666*7c478bd9Sstevel@tonic-gate grow(); 667*7c478bd9Sstevel@tonic-gate where = ++last_used; 668*7c478bd9Sstevel@tonic-gate } 669*7c478bd9Sstevel@tonic-gate if (tab != NULL) { 670*7c478bd9Sstevel@tonic-gate ++count; 671*7c478bd9Sstevel@tonic-gate setEntryExp(where, obj, initialLoad); 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate if (enumMode.flag) 674*7c478bd9Sstevel@tonic-gate enumTouch(where); 675*7c478bd9Sstevel@tonic-gate tab[where] = new_entry(obj); 676*7c478bd9Sstevel@tonic-gate return (where); 677*7c478bd9Sstevel@tonic-gate } else { 678*7c478bd9Sstevel@tonic-gate return (NULL); 679*7c478bd9Sstevel@tonic-gate } 680*7c478bd9Sstevel@tonic-gate } 681*7c478bd9Sstevel@tonic-gate 682*7c478bd9Sstevel@tonic-gate /* 683*7c478bd9Sstevel@tonic-gate * Replaces object at specified location by given entry. 684*7c478bd9Sstevel@tonic-gate * Returns TRUE if replacement successful; FALSE otherwise. 685*7c478bd9Sstevel@tonic-gate * There must something already at the specified location, otherwise, 686*7c478bd9Sstevel@tonic-gate * replacement fails. Copy is not made of the input. 687*7c478bd9Sstevel@tonic-gate * The pre-existing entry is freed. 688*7c478bd9Sstevel@tonic-gate */ 689*7c478bd9Sstevel@tonic-gate bool_t 690*7c478bd9Sstevel@tonic-gate db_table::replace_entry(entryp where, entry_object * obj) 691*7c478bd9Sstevel@tonic-gate { 692*7c478bd9Sstevel@tonic-gate ASSERTWHELD(table); 693*7c478bd9Sstevel@tonic-gate if (where < DB_TABLE_START || where >= table_size || 694*7c478bd9Sstevel@tonic-gate tab == NULL || tab[where] == NULL) 695*7c478bd9Sstevel@tonic-gate return (FALSE); 696*7c478bd9Sstevel@tonic-gate /* (Re-)set the entry TTL */ 697*7c478bd9Sstevel@tonic-gate setEntryExp(where, obj, 0); 698*7c478bd9Sstevel@tonic-gate 699*7c478bd9Sstevel@tonic-gate if (enumMode.flag) 700*7c478bd9Sstevel@tonic-gate enumTouch(where); 701*7c478bd9Sstevel@tonic-gate free_entry(tab[where]); 702*7c478bd9Sstevel@tonic-gate tab[where] = obj; 703*7c478bd9Sstevel@tonic-gate return (TRUE); 704*7c478bd9Sstevel@tonic-gate } 705*7c478bd9Sstevel@tonic-gate 706*7c478bd9Sstevel@tonic-gate /* 707*7c478bd9Sstevel@tonic-gate * Deletes entry at specified location. Returns TRUE if location is valid; 708*7c478bd9Sstevel@tonic-gate * FALSE if location is invalid, or the freed location cannot be added to 709*7c478bd9Sstevel@tonic-gate * the freelist. 'count' is decremented if the deletion occurs. The object 710*7c478bd9Sstevel@tonic-gate * at that location is freed. 711*7c478bd9Sstevel@tonic-gate */ 712*7c478bd9Sstevel@tonic-gate bool_t 713*7c478bd9Sstevel@tonic-gate db_table::delete_entry(entryp where) 714*7c478bd9Sstevel@tonic-gate { 715*7c478bd9Sstevel@tonic-gate bool_t ret = TRUE; 716*7c478bd9Sstevel@tonic-gate 717*7c478bd9Sstevel@tonic-gate ASSERTWHELD(table); 718*7c478bd9Sstevel@tonic-gate if (where < DB_TABLE_START || where >= table_size || 719*7c478bd9Sstevel@tonic-gate tab == NULL || tab[where] == NULL) 720*7c478bd9Sstevel@tonic-gate return (FALSE); 721*7c478bd9Sstevel@tonic-gate if (mapping.expire != NULL) { 722*7c478bd9Sstevel@tonic-gate mapping.expire[where] = 0; 723*7c478bd9Sstevel@tonic-gate } 724*7c478bd9Sstevel@tonic-gate if (enumMode.flag) 725*7c478bd9Sstevel@tonic-gate enumTouch(where); 726*7c478bd9Sstevel@tonic-gate free_entry(tab[where]); 727*7c478bd9Sstevel@tonic-gate tab[where] = NULL; /* very important to set it to null */ 728*7c478bd9Sstevel@tonic-gate --count; 729*7c478bd9Sstevel@tonic-gate if (where == last_used) { /* simple case, deleting from end */ 730*7c478bd9Sstevel@tonic-gate --last_used; 731*7c478bd9Sstevel@tonic-gate return (TRUE); 732*7c478bd9Sstevel@tonic-gate } else { 733*7c478bd9Sstevel@tonic-gate return (freelist.push(where)); 734*7c478bd9Sstevel@tonic-gate } 735*7c478bd9Sstevel@tonic-gate return (ret); 736*7c478bd9Sstevel@tonic-gate } 737*7c478bd9Sstevel@tonic-gate 738*7c478bd9Sstevel@tonic-gate /* 739*7c478bd9Sstevel@tonic-gate * Returns statistics of table. 740*7c478bd9Sstevel@tonic-gate * [vector_size][table_size][last_used][count][freelist]. 741*7c478bd9Sstevel@tonic-gate * It is up to the caller to free the returned vector when his is through. 742*7c478bd9Sstevel@tonic-gate * The free list is included if 'fl' is TRUE. 743*7c478bd9Sstevel@tonic-gate */ 744*7c478bd9Sstevel@tonic-gate long * 745*7c478bd9Sstevel@tonic-gate db_table::stats(bool_t include_freelist) 746*7c478bd9Sstevel@tonic-gate { 747*7c478bd9Sstevel@tonic-gate long *answer; 748*7c478bd9Sstevel@tonic-gate 749*7c478bd9Sstevel@tonic-gate READLOCK(this, NULL, "r db_table::stats"); 750*7c478bd9Sstevel@tonic-gate if (include_freelist) 751*7c478bd9Sstevel@tonic-gate answer = freelist.stats(3); 752*7c478bd9Sstevel@tonic-gate else { 753*7c478bd9Sstevel@tonic-gate answer = (long *)malloc(3*sizeof (long)); 754*7c478bd9Sstevel@tonic-gate } 755*7c478bd9Sstevel@tonic-gate 756*7c478bd9Sstevel@tonic-gate if (answer) { 757*7c478bd9Sstevel@tonic-gate answer[0] = table_size; 758*7c478bd9Sstevel@tonic-gate answer[1] = last_used; 759*7c478bd9Sstevel@tonic-gate answer[2] = count; 760*7c478bd9Sstevel@tonic-gate } 761*7c478bd9Sstevel@tonic-gate READUNLOCK(this, answer, "ru db_table::stats"); 762*7c478bd9Sstevel@tonic-gate return (answer); 763*7c478bd9Sstevel@tonic-gate } 764*7c478bd9Sstevel@tonic-gate 765*7c478bd9Sstevel@tonic-gate bool_t 766*7c478bd9Sstevel@tonic-gate db_table::configure(char *tablePath) { 767*7c478bd9Sstevel@tonic-gate long i; 768*7c478bd9Sstevel@tonic-gate struct timeval now; 769*7c478bd9Sstevel@tonic-gate char *myself = "db_table::configure"; 770*7c478bd9Sstevel@tonic-gate 771*7c478bd9Sstevel@tonic-gate (void) gettimeofday(&now, NULL); 772*7c478bd9Sstevel@tonic-gate 773*7c478bd9Sstevel@tonic-gate WRITELOCK(this, FALSE, "db_table::configure w"); 774*7c478bd9Sstevel@tonic-gate 775*7c478bd9Sstevel@tonic-gate /* (Re-)initialize from global info */ 776*7c478bd9Sstevel@tonic-gate initMappingStruct(&mapping); 777*7c478bd9Sstevel@tonic-gate 778*7c478bd9Sstevel@tonic-gate /* Retrieve table mapping for this table */ 779*7c478bd9Sstevel@tonic-gate mapping.tm = (__nis_table_mapping_t *)__nis_find_item_mt( 780*7c478bd9Sstevel@tonic-gate tablePath, &ldapMappingList, 0, 0); 781*7c478bd9Sstevel@tonic-gate if (mapping.tm != 0) { 782*7c478bd9Sstevel@tonic-gate __nis_object_dn_t *odn = mapping.tm->objectDN; 783*7c478bd9Sstevel@tonic-gate 784*7c478bd9Sstevel@tonic-gate /* 785*7c478bd9Sstevel@tonic-gate * The mapping.fromLDAP and mapping.toLDAP fields serve as 786*7c478bd9Sstevel@tonic-gate * quick-references that tell us if mapping is enabled. 787*7c478bd9Sstevel@tonic-gate * Hence, initialize them appropriately from the table 788*7c478bd9Sstevel@tonic-gate * mapping objectDN. 789*7c478bd9Sstevel@tonic-gate */ 790*7c478bd9Sstevel@tonic-gate while (odn != 0 && (!mapping.fromLDAP || !mapping.toLDAP)) { 791*7c478bd9Sstevel@tonic-gate if (odn->read.scope != LDAP_SCOPE_UNKNOWN) 792*7c478bd9Sstevel@tonic-gate mapping.fromLDAP = TRUE; 793*7c478bd9Sstevel@tonic-gate if (odn->write.scope != LDAP_SCOPE_UNKNOWN) 794*7c478bd9Sstevel@tonic-gate mapping.toLDAP = TRUE; 795*7c478bd9Sstevel@tonic-gate odn = (__nis_object_dn_t *)odn->next; 796*7c478bd9Sstevel@tonic-gate } 797*7c478bd9Sstevel@tonic-gate 798*7c478bd9Sstevel@tonic-gate /* Set the timeout values */ 799*7c478bd9Sstevel@tonic-gate mapping.initTtlLo = mapping.tm->initTtlLo; 800*7c478bd9Sstevel@tonic-gate mapping.initTtlHi = mapping.tm->initTtlHi; 801*7c478bd9Sstevel@tonic-gate mapping.ttl = mapping.tm->ttl; 802*7c478bd9Sstevel@tonic-gate 803*7c478bd9Sstevel@tonic-gate mapping.objName = sdup(myself, T, mapping.tm->objName); 804*7c478bd9Sstevel@tonic-gate if (mapping.objName == 0 && mapping.tm->objName != 0) { 805*7c478bd9Sstevel@tonic-gate WRITEUNLOCK(this, FALSE, 806*7c478bd9Sstevel@tonic-gate "db_table::configure wu objName"); 807*7c478bd9Sstevel@tonic-gate FATAL3("db_table::configure objName", 808*7c478bd9Sstevel@tonic-gate DB_MEMORY_LIMIT, FALSE); 809*7c478bd9Sstevel@tonic-gate } 810*7c478bd9Sstevel@tonic-gate } 811*7c478bd9Sstevel@tonic-gate 812*7c478bd9Sstevel@tonic-gate /* 813*7c478bd9Sstevel@tonic-gate * In order to initialize the expiration times, we need to know 814*7c478bd9Sstevel@tonic-gate * if 'this' represents a table or a directory. To that end, we 815*7c478bd9Sstevel@tonic-gate * find an entry in the table, and invoke setEntryExp() on it. 816*7c478bd9Sstevel@tonic-gate * As a side effect, setEntryExp() will examine the pseudo-object 817*7c478bd9Sstevel@tonic-gate * in the entry, and set the expireType accordingly. 818*7c478bd9Sstevel@tonic-gate */ 819*7c478bd9Sstevel@tonic-gate if (tab != 0) { 820*7c478bd9Sstevel@tonic-gate for (i = 0; i <= last_used; i++) { 821*7c478bd9Sstevel@tonic-gate if (tab[i] != NULL) { 822*7c478bd9Sstevel@tonic-gate setEntryExp(i, tab[i], 1); 823*7c478bd9Sstevel@tonic-gate break; 824*7c478bd9Sstevel@tonic-gate } 825*7c478bd9Sstevel@tonic-gate } 826*7c478bd9Sstevel@tonic-gate } 827*7c478bd9Sstevel@tonic-gate 828*7c478bd9Sstevel@tonic-gate /* 829*7c478bd9Sstevel@tonic-gate * If mapping from an LDAP repository, make sure we have the 830*7c478bd9Sstevel@tonic-gate * expiration time array. 831*7c478bd9Sstevel@tonic-gate */ 832*7c478bd9Sstevel@tonic-gate if ((mapping.expireType != NIS_TABLE_OBJ || mapping.fromLDAP) && 833*7c478bd9Sstevel@tonic-gate mapping.expire == NULL && table_size > 0 && tab != 0) { 834*7c478bd9Sstevel@tonic-gate db_status stat = allocateExpire(0, table_size); 835*7c478bd9Sstevel@tonic-gate if (stat != DB_SUCCESS) { 836*7c478bd9Sstevel@tonic-gate WRITEUNLOCK(this, FALSE, 837*7c478bd9Sstevel@tonic-gate "db_table::configure wu expire"); 838*7c478bd9Sstevel@tonic-gate FATAL3("db_table::configure expire", 839*7c478bd9Sstevel@tonic-gate stat, FALSE); 840*7c478bd9Sstevel@tonic-gate } 841*7c478bd9Sstevel@tonic-gate } else if (mapping.expireType == NIS_TABLE_OBJ && !mapping.fromLDAP && 842*7c478bd9Sstevel@tonic-gate mapping.expire != NULL) { 843*7c478bd9Sstevel@tonic-gate /* Not using expiration times */ 844*7c478bd9Sstevel@tonic-gate free(mapping.expire); 845*7c478bd9Sstevel@tonic-gate mapping.expire = NULL; 846*7c478bd9Sstevel@tonic-gate } 847*7c478bd9Sstevel@tonic-gate 848*7c478bd9Sstevel@tonic-gate /* 849*7c478bd9Sstevel@tonic-gate * Set initial expire times for entries that don't already have one. 850*7c478bd9Sstevel@tonic-gate * Establish the enumeration expiration time to be the minimum of 851*7c478bd9Sstevel@tonic-gate * all expiration times in the table, though no larger than current 852*7c478bd9Sstevel@tonic-gate * time plus initTtlHi. 853*7c478bd9Sstevel@tonic-gate */ 854*7c478bd9Sstevel@tonic-gate if (mapping.expire != NULL) { 855*7c478bd9Sstevel@tonic-gate int interval = mapping.initTtlHi - mapping.initTtlLo + 1; 856*7c478bd9Sstevel@tonic-gate time_t enumXp = now.tv_sec + mapping.initTtlHi; 857*7c478bd9Sstevel@tonic-gate 858*7c478bd9Sstevel@tonic-gate if (interval > 1) 859*7c478bd9Sstevel@tonic-gate srand48(now.tv_sec); 860*7c478bd9Sstevel@tonic-gate for (i = 0; i <= last_used; i++) { 861*7c478bd9Sstevel@tonic-gate if (tab[i] != NULL && mapping.expire[i] == 0) { 862*7c478bd9Sstevel@tonic-gate if (mapping.expireType == NIS_TABLE_OBJ) { 863*7c478bd9Sstevel@tonic-gate if (interval > 1) 864*7c478bd9Sstevel@tonic-gate mapping.expire[i] = 865*7c478bd9Sstevel@tonic-gate now.tv_sec + 866*7c478bd9Sstevel@tonic-gate (lrand48() % interval); 867*7c478bd9Sstevel@tonic-gate else 868*7c478bd9Sstevel@tonic-gate mapping.expire[i] = 869*7c478bd9Sstevel@tonic-gate now.tv_sec + 870*7c478bd9Sstevel@tonic-gate mapping.initTtlLo; 871*7c478bd9Sstevel@tonic-gate } else { 872*7c478bd9Sstevel@tonic-gate setEntryExp(i, tab[i], 1); 873*7c478bd9Sstevel@tonic-gate } 874*7c478bd9Sstevel@tonic-gate } 875*7c478bd9Sstevel@tonic-gate if (enumXp > mapping.expire[i]) 876*7c478bd9Sstevel@tonic-gate enumXp = mapping.expire[i]; 877*7c478bd9Sstevel@tonic-gate } 878*7c478bd9Sstevel@tonic-gate mapping.enumExpire = enumXp; 879*7c478bd9Sstevel@tonic-gate } 880*7c478bd9Sstevel@tonic-gate 881*7c478bd9Sstevel@tonic-gate WRITEUNLOCK(this, FALSE, "db_table::configure wu"); 882*7c478bd9Sstevel@tonic-gate 883*7c478bd9Sstevel@tonic-gate return (TRUE); 884*7c478bd9Sstevel@tonic-gate } 885*7c478bd9Sstevel@tonic-gate 886*7c478bd9Sstevel@tonic-gate /* Return TRUE if the entry at 'loc' hasn't expired */ 887*7c478bd9Sstevel@tonic-gate bool_t 888*7c478bd9Sstevel@tonic-gate db_table::cacheValid(entryp loc) { 889*7c478bd9Sstevel@tonic-gate bool_t ret; 890*7c478bd9Sstevel@tonic-gate struct timeval now; 891*7c478bd9Sstevel@tonic-gate 892*7c478bd9Sstevel@tonic-gate (void) gettimeofday(&now, 0); 893*7c478bd9Sstevel@tonic-gate 894*7c478bd9Sstevel@tonic-gate READLOCK(this, FALSE, "db_table::cacheValid r"); 895*7c478bd9Sstevel@tonic-gate 896*7c478bd9Sstevel@tonic-gate if (loc < 0 || loc >= table_size || tab == 0 || tab[loc] == 0) 897*7c478bd9Sstevel@tonic-gate ret = FALSE; 898*7c478bd9Sstevel@tonic-gate else if (mapping.expire == 0 || mapping.expire[loc] >= now.tv_sec) 899*7c478bd9Sstevel@tonic-gate ret = TRUE; 900*7c478bd9Sstevel@tonic-gate else 901*7c478bd9Sstevel@tonic-gate ret = FALSE; 902*7c478bd9Sstevel@tonic-gate 903*7c478bd9Sstevel@tonic-gate READUNLOCK(this, ret, "db_table::cacheValid ru"); 904*7c478bd9Sstevel@tonic-gate 905*7c478bd9Sstevel@tonic-gate return (ret); 906*7c478bd9Sstevel@tonic-gate } 907*7c478bd9Sstevel@tonic-gate 908*7c478bd9Sstevel@tonic-gate /* 909*7c478bd9Sstevel@tonic-gate * If the supplied object has the same content as the one at 'loc', 910*7c478bd9Sstevel@tonic-gate * update the expiration time for the latter, and return TRUE. 911*7c478bd9Sstevel@tonic-gate */ 912*7c478bd9Sstevel@tonic-gate bool_t 913*7c478bd9Sstevel@tonic-gate db_table::dupEntry(entry_object *obj, entryp loc) { 914*7c478bd9Sstevel@tonic-gate if (obj == 0 || loc < 0 || loc >= table_size || tab == 0 || 915*7c478bd9Sstevel@tonic-gate tab[loc] == 0) 916*7c478bd9Sstevel@tonic-gate return (FALSE); 917*7c478bd9Sstevel@tonic-gate 918*7c478bd9Sstevel@tonic-gate if (sameEntry(obj, tab[loc])) { 919*7c478bd9Sstevel@tonic-gate setEntryExp(loc, tab[loc], 0); 920*7c478bd9Sstevel@tonic-gate 921*7c478bd9Sstevel@tonic-gate if (enumMode.flag > 0) 922*7c478bd9Sstevel@tonic-gate enumTouch(loc); 923*7c478bd9Sstevel@tonic-gate return (TRUE); 924*7c478bd9Sstevel@tonic-gate } 925*7c478bd9Sstevel@tonic-gate 926*7c478bd9Sstevel@tonic-gate return (FALSE); 927*7c478bd9Sstevel@tonic-gate } 928*7c478bd9Sstevel@tonic-gate 929*7c478bd9Sstevel@tonic-gate /* 930*7c478bd9Sstevel@tonic-gate * If enumeration mode is enabled, we keep a shadow array that initially 931*7c478bd9Sstevel@tonic-gate * starts out the same as 'tab'. Any update activity (add, remove, replace, 932*7c478bd9Sstevel@tonic-gate * or update timestamp) for an entry in the table means we delete the shadow 933*7c478bd9Sstevel@tonic-gate * array pointer. When ending enumeration mode, we return the shadow array. 934*7c478bd9Sstevel@tonic-gate * Any non-NULL entries in the array have not been updated since the start 935*7c478bd9Sstevel@tonic-gate * of the enum mode. 936*7c478bd9Sstevel@tonic-gate * 937*7c478bd9Sstevel@tonic-gate * The indended use is for enumeration of an LDAP container, where we 938*7c478bd9Sstevel@tonic-gate * will update all entries that currently exist in LDAP. The entries we 939*7c478bd9Sstevel@tonic-gate * don't update are those that don't exist in LDAP, and thus should be 940*7c478bd9Sstevel@tonic-gate * removed. 941*7c478bd9Sstevel@tonic-gate * 942*7c478bd9Sstevel@tonic-gate * Note that any LDAP query strictly speaking can be a partial enumeration 943*7c478bd9Sstevel@tonic-gate * (i.e., return more than one match). Since the query might also have 944*7c478bd9Sstevel@tonic-gate * matched multiple local DB entries, we need to do the same work as for 945*7c478bd9Sstevel@tonic-gate * enumeration for any query. In order to avoid having to work on the 946*7c478bd9Sstevel@tonic-gate * whole 'tab' array for simple queries (which we expect usually will 947*7c478bd9Sstevel@tonic-gate * match just one or at most a few entries), we have a "reduced" enum mode, 948*7c478bd9Sstevel@tonic-gate * where the caller supplies a count of the number of DB entries (derived 949*7c478bd9Sstevel@tonic-gate * from db_mindex::satisfy_query() or similar), and then uses enumSetup() 950*7c478bd9Sstevel@tonic-gate * to specify which 'tab' entries we're interested in. 951*7c478bd9Sstevel@tonic-gate */ 952*7c478bd9Sstevel@tonic-gate void 953*7c478bd9Sstevel@tonic-gate db_table::setEnumMode(long enumNum) { 954*7c478bd9Sstevel@tonic-gate char *myself = "setEnumMode"; 955*7c478bd9Sstevel@tonic-gate 956*7c478bd9Sstevel@tonic-gate enumMode.flag++; 957*7c478bd9Sstevel@tonic-gate if (enumMode.flag == 1) { 958*7c478bd9Sstevel@tonic-gate db_status stat; 959*7c478bd9Sstevel@tonic-gate 960*7c478bd9Sstevel@tonic-gate if (enumNum < 0) 961*7c478bd9Sstevel@tonic-gate enumNum = 0; 962*7c478bd9Sstevel@tonic-gate else if (enumNum >= table_size) 963*7c478bd9Sstevel@tonic-gate enumNum = table_size; 964*7c478bd9Sstevel@tonic-gate 965*7c478bd9Sstevel@tonic-gate enumCount.flag = enumNum; 966*7c478bd9Sstevel@tonic-gate 967*7c478bd9Sstevel@tonic-gate stat = allocateEnumArray(0, table_size); 968*7c478bd9Sstevel@tonic-gate 969*7c478bd9Sstevel@tonic-gate if (stat != DB_SUCCESS) { 970*7c478bd9Sstevel@tonic-gate enumMode.flag = 0; 971*7c478bd9Sstevel@tonic-gate enumCount.flag = 0; 972*7c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 973*7c478bd9Sstevel@tonic-gate "%s: No memory for enum check array; entry removal disabled", 974*7c478bd9Sstevel@tonic-gate myself); 975*7c478bd9Sstevel@tonic-gate } 976*7c478bd9Sstevel@tonic-gate } 977*7c478bd9Sstevel@tonic-gate } 978*7c478bd9Sstevel@tonic-gate 979*7c478bd9Sstevel@tonic-gate void 980*7c478bd9Sstevel@tonic-gate db_table::clearEnumMode(void) { 981*7c478bd9Sstevel@tonic-gate if (enumMode.flag > 0) { 982*7c478bd9Sstevel@tonic-gate enumMode.flag--; 983*7c478bd9Sstevel@tonic-gate if (enumMode.flag == 0) { 984*7c478bd9Sstevel@tonic-gate sfree(enumArray.ptr); 985*7c478bd9Sstevel@tonic-gate enumArray.ptr = 0; 986*7c478bd9Sstevel@tonic-gate if (enumCount.flag > 0) { 987*7c478bd9Sstevel@tonic-gate sfree(enumIndex.ptr); 988*7c478bd9Sstevel@tonic-gate enumIndex.ptr = 0; 989*7c478bd9Sstevel@tonic-gate enumCount.flag = 0; 990*7c478bd9Sstevel@tonic-gate } 991*7c478bd9Sstevel@tonic-gate } 992*7c478bd9Sstevel@tonic-gate } 993*7c478bd9Sstevel@tonic-gate } 994*7c478bd9Sstevel@tonic-gate 995*7c478bd9Sstevel@tonic-gate entry_object ** 996*7c478bd9Sstevel@tonic-gate db_table::endEnumMode(long *numEa) { 997*7c478bd9Sstevel@tonic-gate if (enumMode.flag > 0) { 998*7c478bd9Sstevel@tonic-gate enumMode.flag--; 999*7c478bd9Sstevel@tonic-gate if (enumMode.flag == 0) { 1000*7c478bd9Sstevel@tonic-gate entry_obj **ea = (entry_object **)enumArray.ptr; 1001*7c478bd9Sstevel@tonic-gate long nea; 1002*7c478bd9Sstevel@tonic-gate 1003*7c478bd9Sstevel@tonic-gate enumArray.ptr = 0; 1004*7c478bd9Sstevel@tonic-gate 1005*7c478bd9Sstevel@tonic-gate if (enumCount.flag > 0) { 1006*7c478bd9Sstevel@tonic-gate nea = enumCount.flag; 1007*7c478bd9Sstevel@tonic-gate enumCount.flag = 0; 1008*7c478bd9Sstevel@tonic-gate sfree(enumIndex.ptr); 1009*7c478bd9Sstevel@tonic-gate enumIndex.ptr = 0; 1010*7c478bd9Sstevel@tonic-gate } else { 1011*7c478bd9Sstevel@tonic-gate nea = table_size; 1012*7c478bd9Sstevel@tonic-gate } 1013*7c478bd9Sstevel@tonic-gate 1014*7c478bd9Sstevel@tonic-gate if (numEa != 0) 1015*7c478bd9Sstevel@tonic-gate *numEa = nea; 1016*7c478bd9Sstevel@tonic-gate 1017*7c478bd9Sstevel@tonic-gate return (ea); 1018*7c478bd9Sstevel@tonic-gate } 1019*7c478bd9Sstevel@tonic-gate } 1020*7c478bd9Sstevel@tonic-gate 1021*7c478bd9Sstevel@tonic-gate if (numEa != 0) 1022*7c478bd9Sstevel@tonic-gate *numEa = 0; 1023*7c478bd9Sstevel@tonic-gate 1024*7c478bd9Sstevel@tonic-gate return (0); 1025*7c478bd9Sstevel@tonic-gate } 1026*7c478bd9Sstevel@tonic-gate 1027*7c478bd9Sstevel@tonic-gate /* 1028*7c478bd9Sstevel@tonic-gate * Set the appropriate entry in the enum array to NULL. 1029*7c478bd9Sstevel@tonic-gate */ 1030*7c478bd9Sstevel@tonic-gate void 1031*7c478bd9Sstevel@tonic-gate db_table::enumTouch(entryp loc) { 1032*7c478bd9Sstevel@tonic-gate if (loc < 0 || loc >= table_size) 1033*7c478bd9Sstevel@tonic-gate return; 1034*7c478bd9Sstevel@tonic-gate 1035*7c478bd9Sstevel@tonic-gate if (enumMode.flag > 0) { 1036*7c478bd9Sstevel@tonic-gate if (enumCount.flag < 1) { 1037*7c478bd9Sstevel@tonic-gate ((entry_object **)enumArray.ptr)[loc] = 0; 1038*7c478bd9Sstevel@tonic-gate } else { 1039*7c478bd9Sstevel@tonic-gate int i; 1040*7c478bd9Sstevel@tonic-gate 1041*7c478bd9Sstevel@tonic-gate for (i = 0; i < enumCount.flag; i++) { 1042*7c478bd9Sstevel@tonic-gate if (loc == ((entryp *)enumIndex.ptr)[i]) { 1043*7c478bd9Sstevel@tonic-gate ((entry_object **)enumArray.ptr)[i] = 0; 1044*7c478bd9Sstevel@tonic-gate break; 1045*7c478bd9Sstevel@tonic-gate } 1046*7c478bd9Sstevel@tonic-gate } 1047*7c478bd9Sstevel@tonic-gate } 1048*7c478bd9Sstevel@tonic-gate } 1049*7c478bd9Sstevel@tonic-gate } 1050*7c478bd9Sstevel@tonic-gate 1051*7c478bd9Sstevel@tonic-gate /* 1052*7c478bd9Sstevel@tonic-gate * Add the entry indicated by 'loc' to the enumIndex array, at 'index'. 1053*7c478bd9Sstevel@tonic-gate */ 1054*7c478bd9Sstevel@tonic-gate void 1055*7c478bd9Sstevel@tonic-gate db_table::enumSetup(entryp loc, long index) { 1056*7c478bd9Sstevel@tonic-gate if (enumMode.flag == 0 || loc < 0 || loc >= table_size || 1057*7c478bd9Sstevel@tonic-gate index < 0 || index >= enumCount.flag) 1058*7c478bd9Sstevel@tonic-gate return; 1059*7c478bd9Sstevel@tonic-gate 1060*7c478bd9Sstevel@tonic-gate ((entryp *)enumIndex.ptr)[index] = loc; 1061*7c478bd9Sstevel@tonic-gate ((entry_object **)enumArray.ptr)[index] = tab[loc]; 1062*7c478bd9Sstevel@tonic-gate } 1063*7c478bd9Sstevel@tonic-gate 1064*7c478bd9Sstevel@tonic-gate /* 1065*7c478bd9Sstevel@tonic-gate * Touch, i.e., update the expiration time for the entry. Also, if enum 1066*7c478bd9Sstevel@tonic-gate * mode is in effect, mark the entry used for enum purposes. 1067*7c478bd9Sstevel@tonic-gate */ 1068*7c478bd9Sstevel@tonic-gate void 1069*7c478bd9Sstevel@tonic-gate db_table::touchEntry(entryp loc) { 1070*7c478bd9Sstevel@tonic-gate if (loc < 0 || loc >= table_size || tab == 0 || tab[loc] == 0) 1071*7c478bd9Sstevel@tonic-gate return; 1072*7c478bd9Sstevel@tonic-gate 1073*7c478bd9Sstevel@tonic-gate setEntryExp(loc, tab[loc], 0); 1074*7c478bd9Sstevel@tonic-gate 1075*7c478bd9Sstevel@tonic-gate enumTouch(loc); 1076*7c478bd9Sstevel@tonic-gate } 1077*7c478bd9Sstevel@tonic-gate 1078*7c478bd9Sstevel@tonic-gate /* ************************* pickle_table ********************* */ 1079*7c478bd9Sstevel@tonic-gate /* Does the actual writing to/from file specific for db_table structure. */ 1080*7c478bd9Sstevel@tonic-gate /* 1081*7c478bd9Sstevel@tonic-gate * This was a static earlier with the func name being transfer_aux. The 1082*7c478bd9Sstevel@tonic-gate * backup and restore project needed this to copy files over. 1083*7c478bd9Sstevel@tonic-gate */ 1084*7c478bd9Sstevel@tonic-gate bool_t 1085*7c478bd9Sstevel@tonic-gate transfer_aux_table(XDR* x, pptr dp) 1086*7c478bd9Sstevel@tonic-gate { 1087*7c478bd9Sstevel@tonic-gate return (xdr_db_table(x, (db_table*) dp)); 1088*7c478bd9Sstevel@tonic-gate } 1089*7c478bd9Sstevel@tonic-gate 1090*7c478bd9Sstevel@tonic-gate class pickle_table: public pickle_file { 1091*7c478bd9Sstevel@tonic-gate public: 1092*7c478bd9Sstevel@tonic-gate pickle_table(char *f, pickle_mode m) : pickle_file(f, m) {} 1093*7c478bd9Sstevel@tonic-gate 1094*7c478bd9Sstevel@tonic-gate /* Transfers db_table structure pointed to by dp to/from file. */ 1095*7c478bd9Sstevel@tonic-gate int transfer(db_table* dp) 1096*7c478bd9Sstevel@tonic-gate { return (pickle_file::transfer((pptr) dp, &transfer_aux_table)); } 1097*7c478bd9Sstevel@tonic-gate }; 1098*7c478bd9Sstevel@tonic-gate 1099*7c478bd9Sstevel@tonic-gate /* 1100*7c478bd9Sstevel@tonic-gate * Writes the contents of table, including the all the entries, into the 1101*7c478bd9Sstevel@tonic-gate * specified file in XDR format. May need to change this to use APPEND 1102*7c478bd9Sstevel@tonic-gate * mode instead. 1103*7c478bd9Sstevel@tonic-gate */ 1104*7c478bd9Sstevel@tonic-gate int 1105*7c478bd9Sstevel@tonic-gate db_table::dump(char *file) 1106*7c478bd9Sstevel@tonic-gate { 1107*7c478bd9Sstevel@tonic-gate int ret; 1108*7c478bd9Sstevel@tonic-gate READLOCK(this, -1, "r db_table::dump"); 1109*7c478bd9Sstevel@tonic-gate pickle_table f(file, PICKLE_WRITE); /* may need to use APPEND mode */ 1110*7c478bd9Sstevel@tonic-gate int status = f.transfer(this); 1111*7c478bd9Sstevel@tonic-gate 1112*7c478bd9Sstevel@tonic-gate if (status == 1) 1113*7c478bd9Sstevel@tonic-gate ret = -1; 1114*7c478bd9Sstevel@tonic-gate else 1115*7c478bd9Sstevel@tonic-gate ret = status; 1116*7c478bd9Sstevel@tonic-gate READUNLOCK(this, ret, "ru db_table::dump"); 1117*7c478bd9Sstevel@tonic-gate } 1118*7c478bd9Sstevel@tonic-gate 1119*7c478bd9Sstevel@tonic-gate /* Constructor that loads in the table from the given file */ 1120*7c478bd9Sstevel@tonic-gate db_table::db_table(char *file) : freelist() 1121*7c478bd9Sstevel@tonic-gate { 1122*7c478bd9Sstevel@tonic-gate pickle_table f(file, PICKLE_READ); 1123*7c478bd9Sstevel@tonic-gate tab = NULL; 1124*7c478bd9Sstevel@tonic-gate table_size = last_used = count = 0; 1125*7c478bd9Sstevel@tonic-gate 1126*7c478bd9Sstevel@tonic-gate /* load table */ 1127*7c478bd9Sstevel@tonic-gate if (f.transfer(this) < 0) { 1128*7c478bd9Sstevel@tonic-gate /* fell through, something went wrong, initialize to null */ 1129*7c478bd9Sstevel@tonic-gate tab = NULL; 1130*7c478bd9Sstevel@tonic-gate table_size = last_used = count = 0; 1131*7c478bd9Sstevel@tonic-gate freelist.init(); 1132*7c478bd9Sstevel@tonic-gate } 1133*7c478bd9Sstevel@tonic-gate 1134*7c478bd9Sstevel@tonic-gate db_table_ldap_init(); 1135*7c478bd9Sstevel@tonic-gate initMappingStruct(&mapping); 1136*7c478bd9Sstevel@tonic-gate } 1137*7c478bd9Sstevel@tonic-gate 1138*7c478bd9Sstevel@tonic-gate /* Returns whether location is valid. */ 1139*7c478bd9Sstevel@tonic-gate bool_t db_table::entry_exists_p(entryp i) { 1140*7c478bd9Sstevel@tonic-gate bool_t ret = FALSE; 1141*7c478bd9Sstevel@tonic-gate READLOCK(this, FALSE, "r db_table::entry_exists_p"); 1142*7c478bd9Sstevel@tonic-gate if (tab != NULL && i < table_size) 1143*7c478bd9Sstevel@tonic-gate ret = tab[i] != NULL; 1144*7c478bd9Sstevel@tonic-gate READUNLOCK(this, ret, "ru db_table::entry_exists_p"); 1145*7c478bd9Sstevel@tonic-gate return (ret); 1146*7c478bd9Sstevel@tonic-gate } 1147*7c478bd9Sstevel@tonic-gate 1148*7c478bd9Sstevel@tonic-gate /* Empty free list */ 1149*7c478bd9Sstevel@tonic-gate void db_free_list::init() { 1150*7c478bd9Sstevel@tonic-gate WRITELOCKV(this, "w db_free_list::init"); 1151*7c478bd9Sstevel@tonic-gate head = NULL; 1152*7c478bd9Sstevel@tonic-gate count = 0; 1153*7c478bd9Sstevel@tonic-gate WRITEUNLOCKV(this, "wu db_free_list::init"); 1154*7c478bd9Sstevel@tonic-gate } 1155