Print this page
5910 libnisdb won't build with modern GCC
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libnisdb/db_mindex3.cc
+++ new/usr/src/lib/libnisdb/db_mindex3.cc
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 + * Copyright 2015 Gary Mills
22 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 24 * Use is subject to license terms.
25 + *
26 + * Copyright 2015 RackTop Systems.
24 27 */
25 28
26 29 #include <sys/types.h>
27 30 #include <time.h>
28 31 #include <sys/time.h>
29 32 #include <lber.h>
30 33 #include <ldap.h>
31 34 #include <signal.h>
32 35 #include <pthread.h>
33 36 #include "db_headers.h"
34 37 #include "db.h"
35 38 #include "db_mindex.h"
36 39 #include "db_dictionary.h"
37 40 #include "nisdb_mt.h"
38 41 #include "ldap_map.h"
39 42 #include "ldap_glob.h"
40 43 #include "ldap_util.h"
41 44
42 45
43 46 extern db_dictionary *InUseDictionary;
44 47
45 48
46 49 extern "C" {
47 50
48 51 typedef struct {
49 52 db_mindex *mindex;
50 53 __nis_table_mapping_t *t;
51 54 db_query *qin;
52 55 db_query *q;
53 56 char *dbId;
54 57 nis_object *dirObj;
55 58 int isDeferred;
56 59 char *tableName;
57 60 } __entries_from_ldap_arg_t;
58 61
59 62 static void *entriesFromLDAPthread(void *);
60 63
61 64 }
62 65
63 66 int entriesFromLDAPreal(__entries_from_ldap_arg_t *);
64 67
65 68 #ifdef SET_ENTRY_FLAGS
66 69 static uint_t
67 70 entryFlagsFromTable(uint_t tf) {
68 71 uint_t ef = 0;
69 72
70 73 if ((tf & TA_BINARY) != 0)
71 74 ef |= EN_BINARY;
72 75 if ((tf & TA_CRYPT) != 0)
73 76 ef |= EN_CRYPT;
74 77 if ((tf & TA_XDR) != 0)
75 78 ef |= EN_XDR;
76 79 if ((tf & TA_ASN1) != 0)
77 80 ef |= EN_ASN1;
78 81
79 82 return (ef);
80 83 }
81 84 #endif /* SET_ENTRY_FLAGS */
82 85
83 86 static void setOid(nis_object *obj);
84 87
85 88 /*
86 89 * Retrieve container entries from LDAP per 't' and 'qin'/'q'.
87 90 * This is a helper function for db_mindex::queryLDAP(); see
88 91 * that function for details of the parameters (except doAsynch).
89 92 *
90 93 * If 'doAsynch' is set, and the retrieval is an enumeration
91 94 * (qin == NULL), the retrieval is performed in a detached
92 95 * thread. In this case, the return code just reflects the
93 96 * setup and launch of the detached thread. Retrieval will
94 97 * complete asynchronously.
95 98 */
96 99 int
97 100 db_mindex::entriesFromLDAP(__nis_table_mapping_t *t, db_query *qin, db_query *q,
98 101 char *dbId, nis_object *dirObj, int doAsynch) {
99 102 __entries_from_ldap_arg_t *arg;
100 103 int stat;
101 104 db_status dstat;
102 105 const char *myself = "db_mindex::entriesFromLDAP";
103 106
104 107 arg = (__entries_from_ldap_arg_t *)am(myself, sizeof (*arg));
105 108 if (arg == 0) {
106 109 freeQuery(q);
107 110 if (dirObj != 0)
108 111 nis_destroy_object(dirObj);
109 112 return (LDAP_NO_MEMORY);
110 113 }
111 114
112 115 arg->mindex = this;
113 116 arg->t = t;
114 117 arg->qin = qin;
115 118 arg->q = q;
116 119 arg->dbId = dbId;
117 120 arg->dirObj = dirObj;
118 121 arg->tableName = t->objName;
119 122
120 123 /*
121 124 * Check if an enumeration thread is running; if so, then regardless
122 125 * of whether or not the current operation is an enumeration, we
123 126 * just return success, and let our caller get the data from the
124 127 * existing (deferred) DB.
125 128 */
126 129 (void) mutex_lock(&table->mapping.enumLock);
127 130 if (table->mapping.enumTid != 0) {
128 131 int doReturn = 0;
129 132
130 133 stat = pthread_kill(table->mapping.enumTid, 0);
131 134 if (stat == ESRCH) {
132 135 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
133 136 "%s: Enumeration thread %d not found for \"%s\"; exit status = %d (%s)",
134 137 myself, table->mapping.enumTid,
135 138 NIL(t->objName), table->mapping.enumStat,
136 139 ldap_err2string(table->mapping.enumStat));
137 140 /* Reflect the fact that no enum thread is running */
138 141 table->mapping.enumTid = 0;
139 142 table->mapping.enumStat = -1;
140 143 /* Cleanup deferred mode */
141 144 if (table->mapping.enumDeferred) {
142 145 dstat = InUseDictionary->commit(t->objPath);
143 146 if (dstat == DB_SUCCESS) {
144 147 table->mapping.enumDeferred = 0;
145 148 } else {
146 149 logmsg(MSG_NOTIMECHECK, LOG_ERR,
147 150 "%s: DB error %d committing \"%s\"",
148 151 myself, dstat, NIL(t->objName));
149 152 }
150 153 }
151 154 } else if (stat == 0) {
152 155 logmsg(MSG_NOTIMECHECK, LOG_INFO,
153 156 "%s: Enumeration thread %d already running for \"%s\"",
154 157 myself, table->mapping.enumTid,
155 158 NIL(t->objName));
156 159 stat = LDAP_SUCCESS;
157 160 doReturn = 1;
158 161 } else {
159 162 logmsg(MSG_NOTIMECHECK, LOG_INFO,
160 163 "%s: Error %d looking for enumeration thread %d for \"%s\"",
161 164 myself, stat, table->mapping.enumTid,
162 165 NIL(t->objName));
163 166 doReturn = 1;
164 167 stat = LDAP_OPERATIONS_ERROR;
165 168 }
166 169 if (doReturn) {
167 170 (void) mutex_unlock(&table->mapping.enumLock);
168 171 sfree(arg);
169 172 freeQuery(q);
170 173 if (dirObj != 0)
171 174 nis_destroy_object(dirObj);
172 175 return (stat);
173 176 }
174 177 }
175 178
176 179 /*
177 180 * If we're enumerating (and hence expect that retrieving all data,
178 181 * and updating the local DB, might take a while), create a deferred-
179 182 * update table that clients can use while we are updating the real
180 183 * one.
181 184 */
182 185 if (doAsynch && qin == 0) {
183 186 if ((dstat = InUseDictionary->defer(t->objPath)) ==
184 187 DB_SUCCESS) {
185 188 arg->isDeferred = 1;
186 189 table->mapping.enumDeferred = 1;
187 190 } else {
188 191 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
189 192 "%s: Unable to defer updates for \"%s\" (status=%d);"
190 193 " updating in place",
191 194 myself, NIL(t->objName), dstat);
192 195 arg->isDeferred = 0;
193 196 table->mapping.enumDeferred = 0;
194 197 }
195 198 } else {
196 199 arg->isDeferred = 0;
197 200 table->mapping.enumDeferred = 0;
198 201 }
199 202
200 203 /* If enumerating, perform the operation in a separate thread */
201 204 if (doAsynch && qin == 0) {
202 205 pthread_t tid;
203 206 pthread_attr_t attr;
204 207
205 208 (void) pthread_attr_init(&attr);
206 209 #ifdef FORCE_SYNCHRONOUS
↓ open down ↓ |
173 lines elided |
↑ open up ↑ |
207 210 #else
208 211 (void) pthread_attr_setdetachstate(&attr,
209 212 PTHREAD_CREATE_DETACHED);
210 213 #endif /* FORCE_SYNCHRONOUS */
211 214 stat = pthread_create(&tid, &attr, entriesFromLDAPthread, arg);
212 215 if (stat != 0) {
213 216 (void) mutex_unlock(&table->mapping.enumLock);
214 217 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
215 218 "%s: Error %d creating new thread; using current one",
216 219 myself, stat);
217 - stat = (int)entriesFromLDAPthread(arg);
220 + stat = entriesFromLDAPreal(arg);
218 221 return (stat);
219 222 }
220 223
221 224 table->mapping.enumTid = tid;
222 225 table->mapping.enumStat = -1;
223 226
224 227 /*
225 228 * We're now returning to the caller, who will get data
226 229 * from:
227 230 *
228 231 * The deferred DB, if an enumeration thread already
229 232 * was running, and deferred mode was on, or
230 233 *
231 234 * The original DB, if we just started an enumeration
232 235 * thread. In this case, our caller (several levels up)
233 236 * is holding a lock on the db_mindex/db_table, which
234 237 * means that the enum thread will have to wait for
235 238 * our caller once it's done the LDAP retrieval, and
236 239 * wants to update the DB.
237 240 */
238 241 (void) mutex_unlock(&table->mapping.enumLock);
239 242 stat = LDAP_SUCCESS;
240 243 #ifdef FORCE_SYNCHRONOUS
241 244 {
242 245 int tstat;
243 246
244 247 stat = pthread_join(tid, (void **)&tstat);
245 248 if (stat == 0) {
246 249 stat = tstat;
247 250 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
248 251 "%s: thread %d => %d",
249 252 myself, tid, tstat);
↓ open down ↓ |
22 lines elided |
↑ open up ↑ |
250 253 } else {
251 254 logmsg(MSG_NOTIMECHECK, LOG_ERR,
252 255 "%s: pthread_join(%d) => %d",
253 256 myself, tid, stat);
254 257 stat = LDAP_OPERATIONS_ERROR;
255 258 }
256 259 }
257 260 #endif /* FORCE_SYNCHRONOUS */
258 261 } else {
259 262 (void) mutex_unlock(&table->mapping.enumLock);
260 - stat = (int)entriesFromLDAPthread(arg);
263 + stat = entriesFromLDAPreal(arg);
261 264 }
262 265
263 266 return (stat);
264 267 }
265 268
266 269 extern "C" {
267 270
268 271 /*
269 272 * We use this 'extern "C"' function in order to make sure that
270 273 * pthread_create() doesn't have any problems trying to invoke a
271 274 * C++ function.
272 275 */
273 276 static void *
274 277 entriesFromLDAPthread(void *voidarg) {
275 278 __entries_from_ldap_arg_t *arg;
276 - int stat;
277 279 db *dbase;
278 280 db_table_desc *tbl = 0;
279 281 char *tableName;
280 282
281 283 arg = (__entries_from_ldap_arg_t *)voidarg;
282 284
283 285 /* Lock to prevent removal */
284 286 (void) __nis_lock_db_table(arg->tableName, 1, 0,
285 287 "entriesFromLDAPthread");
286 288
287 289 /*
288 290 * It's possible that the db_mindex for the table has changed,
289 291 * or disappeared, between now and the time when our parent
290 292 * thread released its lock on the table. Hence, we search the
291 293 * dictionary to re-acquire the 'db', and the db_mindex.
292 294 */
293 295 tableName = internalTableName(arg->tableName);
294 296 if (tableName != 0) {
295 297 #ifdef NISDB_LDAP_DEBUG
296 298 db_mindex *oldMindex = arg->mindex;
297 299 #endif /* NISDB_LDAP_DEBUG */
298 300
299 301 dbase = InUseDictionary->find_table(tableName, &tbl, FALSE);
300 302 if (dbase != 0)
301 303 arg->mindex = dbase->mindex();
302 304 else
303 305 arg->mindex = 0;
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
304 306 #ifdef NISDB_LDAP_DEBUG
305 307 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
306 308 "entriesFromLDAPthread: %s -> %s -> 0x%x (0x%x)",
307 309 NIL(arg->tableName), NIL(tableName),
308 310 arg->mindex, oldMindex);
309 311 #endif /* NISDB_LDAP_DEBUG */
310 312 sfree(tableName);
311 313 tableName = 0;
312 314 }
313 315
314 - stat = entriesFromLDAPreal(arg);
316 + (void) entriesFromLDAPreal(arg);
315 317
316 318 (void) __nis_ulock_db_table(arg->tableName, 1, 0,
317 319 "entriesFromLDAPthread");
318 320
319 321 freeQuery(arg->q);
320 322 if (arg->dirObj != 0)
321 323 nis_destroy_object(arg->dirObj);
322 324 sfree(arg);
323 - return ((void *)stat);
325 + return (NULL);
324 326 }
325 327
326 328 }
327 329
328 330 int
329 331 entriesFromLDAPreal(__entries_from_ldap_arg_t *arg) {
330 332 db_mindex *mindex;
331 333 db_table *table;
332 334 __nis_table_mapping_t *t;
333 335 db_query *q, *qin;
334 336 char *dbId;
335 337 nis_object *dirObj;
336 338 int i, na, nau, nq = 0, xid = 0;
337 339 int ret, stat = LDAP_SUCCESS, stat2, stat3;
338 340 int lstat;
339 341 __nis_obj_attr_t **oa = 0;
340 342 db_query **res;
341 343 entry_object **ea;
342 344 long numEa;
343 345 bool_t doEnum;
344 346 db_status dstat;
345 347 struct timeval start;
346 348 const char *myself =
347 349 "db_mindex::entriesFromLDAPreal";
348 350
349 351 if (arg == 0)
350 352 return (LDAP_PARAM_ERROR);
351 353 mindex = arg->mindex;
352 354 t = arg->t;
353 355 q = arg->q;
354 356 qin = arg->qin;
355 357 dbId = arg->dbId;
356 358 dirObj = arg->dirObj;
357 359
358 360 table = (mindex != 0) ? mindex->getTable() : 0;
359 361
360 362 if (mindex == 0 || t == 0 || table == 0) {
361 363 /* We haven't done anything, so rollback should be OK */
362 364 if (arg->isDeferred && t != 0) {
363 365 dstat = InUseDictionary->rollback(t->objPath);
364 366 if (dstat != DB_SUCCESS) {
365 367 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
366 368 "%s: DB error %d rolling back \"%s\"",
367 369 myself, dstat, NIL(t->objName));
368 370 /*
369 371 * Had rollback succeeded, the 'table'
370 372 * would have disappeared. However, since
371 373 * rollback failed, we need to update the
372 374 * table->mapping.enum* fields.
373 375 */
374 376 if (table != 0) {
375 377 (void) mutex_lock(&table->
376 378 mapping.enumLock);
377 379 table->mapping.enumStat =
378 380 LDAP_PARAM_ERROR;
379 381 table->mapping.enumTime = 0;
380 382 table->mapping.enumEntries = 0;
381 383 table->mapping.enumTid = 0;
382 384 (void) mutex_unlock(&table->
383 385 mapping.enumLock);
384 386 }
385 387 }
386 388 }
387 389 return (LDAP_PARAM_ERROR);
388 390 }
389 391
390 392 if (qin == 0)
391 393 logmsg(MSG_NOTIMECHECK, LOG_INFO, "%s: enumerating \"%s%s%s\"",
392 394 myself, dbId ? dbId : "", dbId ? ":" : "",
393 395 NIL(t->objName));
394 396
395 397 (void) gettimeofday(&start, 0);
396 398
397 399 /* Getting table entries */
398 400 res = mapFromLDAP(t, q, &nq, dbId, &stat, &oa);
399 401 #ifdef NISDB_LDAP_DEBUG
400 402 logmsg(MSG_ALWAYS, LOG_INFO,
401 403 "%s: mapFromLDAP() => 0x%x, status=%d %s; nq = %d",
402 404 myself, res, stat, stat == LDAP_SUCCESS ? "" :
403 405 ldap_err2string(stat), nq);
404 406 #endif /* NISDB_LDAP_DEBUG */
405 407
406 408 /*
407 409 * Keep track of the number of NIS+ entries we got back;
408 410 * note that the number of LDAP entries may have been
409 411 * smaller or larger.
410 412 */
411 413 (void) mutex_lock(&table->mapping.enumLock);
412 414 table->mapping.enumEntries = nq;
413 415 (void) mutex_unlock(&table->mapping.enumLock);
414 416
415 417 /*
416 418 * If we get LDAP_NO_SUCH_OBJECT, we need to delete the entries
417 419 * in the table, so we can't just return.
418 420 */
419 421 if (res == 0 && stat != LDAP_NO_SUCH_OBJECT) {
420 422 logmsg(MSG_NOTIMECHECK, LOG_INFO,
421 423 "%s: mapFromLDAP() => 0x0, status=%d (%s)",
422 424 myself, stat, ldap_err2string(stat));
423 425 if (arg->isDeferred) {
424 426 dstat = InUseDictionary->rollback(t->objPath);
425 427 if (dstat != DB_SUCCESS) {
426 428 struct timeval end;
427 429
428 430 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
429 431 "%s: DB error %d rolling back \"%s\"",
430 432 myself, dstat, NIL(t->objName));
431 433 /*
432 434 * Had rollback succeeded, the 'table'
433 435 * would have disappeared. However, since
434 436 * rollback failed, we need to update the
435 437 * table->mapping.enum* fields.
436 438 */
437 439 (void) mutex_lock(&table->mapping.enumLock);
438 440 table->mapping.enumStat = stat;
439 441 (void) gettimeofday(&end, 0);
440 442 end.tv_sec -= start.tv_sec;
441 443 end.tv_usec -= start.tv_usec;
442 444 if (end.tv_usec < 0) {
443 445 end.tv_usec += 1000000;
444 446 end.tv_sec -= 1;
445 447 }
446 448 table->mapping.enumTime =
447 449 1000000*end.tv_sec + end.tv_usec;
448 450 table->mapping.enumTid = 0;
449 451 (void) mutex_unlock(&table->mapping.enumLock);
450 452 }
451 453 }
452 454 return (stat);
453 455 }
454 456
455 457 /*
456 458 * Need to disable write-through to LDAP, for which we need a lock
457 459 * on our db_mindex ('mindex'); we're also updating the table, so
458 460 * we need a write lock on that as well. However, before locking the
459 461 * mindex, we need to maintain lock integrity by acquiring the
460 462 * trans log lock. Note that actually beginning a transaction is
461 463 * expensive, so we defer that until we know that we really need
462 464 * to update.
463 465 */
464 466 lstat = lockTransLog(myself, 1, 1);
465 467 if (lstat != 0) {
466 468 if (lstat == EBUSY)
467 469 logmsg(MSG_NOTIMECHECK, LOG_INFO,
468 470 "%s: transaction log busy; no LDAP update for \"%s\"",
469 471 myself, NIL(t->objName));
470 472 else
471 473 logmsg(MSG_NOTIMECHECK, LOG_ERR,
472 474 "%s: Error %d locking transaction log; no LDAP update for \"%s\"",
473 475 myself, lstat, NIL(t->objName));
474 476 if (arg->isDeferred) {
475 477 dstat = InUseDictionary->rollback(t->objPath);
476 478 if (dstat != DB_SUCCESS) {
477 479 struct timeval end;
478 480
479 481 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
480 482 "%s: DB error %d rolling back \"%s\"",
481 483 myself, dstat, NIL(t->objName));
482 484 /*
483 485 * Had rollback succeeded, the 'table'
484 486 * would have disappeared. However, since
485 487 * rollback failed, we need to update the
486 488 * table->mapping.enum* fields.
487 489 */
488 490 (void) mutex_lock(&table->mapping.enumLock);
489 491 table->mapping.enumStat = LDAP_OPERATIONS_ERROR;
490 492 (void) gettimeofday(&end, 0);
491 493 end.tv_sec -= start.tv_sec;
492 494 end.tv_usec -= start.tv_usec;
493 495 if (end.tv_usec < 0) {
494 496 end.tv_usec += 1000000;
495 497 end.tv_sec -= 1;
496 498 }
497 499 table->mapping.enumTime = 1000000*end.tv_sec +
498 500 end.tv_usec;
499 501 table->mapping.enumTid = 0;
500 502 (void) mutex_unlock(&table->mapping.enumLock);
501 503 }
502 504 }
503 505 return (LDAP_OPERATIONS_ERROR);
504 506 }
505 507
506 508 /*
507 509 * If we have any updates, we'll call db::sync_log, which write-
508 510 * locks the 'db' instance. In order to avoid a dead-lock with
509 511 * threads performing a DB lookup (which will lock the 'db' and
510 512 * then the 'db_mindex'), we need hence need to lock in the
511 513 * following order:
512 514 *
513 515 * trans.log (already holding that one)
514 516 * db
515 517 * db_mindex
516 518 * db_table
517 519 */
518 520 TRYWRITELOCK(((db *)mindex->getDbPtr()), stat,
519 521 "w db db_mindex::entriesFromLDAPreal");
520 522 if (stat == 0) {
521 523 TRYWRITELOCK(mindex, stat2, "w db_mindex::entriesFromLDAPreal");
522 524 if (stat2 == 0) {
523 525 TRYWRITELOCK(table, stat3,
524 526 "table w db_mindex::entriesFromLDAPreal");
525 527 }
526 528 }
527 529
528 530 if (stat != 0 || stat2 != 0 || stat3 != 0) {
529 531 if (stat != 0) {
530 532 if (stat == EBUSY)
531 533 logmsg(MSG_NOTIMECHECK, LOG_INFO,
532 534 "%s: 'db' busy; no LDAP update for \"%s\"",
533 535 myself, NIL(t->objName));
534 536 else
535 537 logmsg(MSG_NOTIMECHECK, LOG_ERR,
536 538 "%s: 'db' lock error %d; no LDAP update for \"%s\"",
537 539 myself, stat, NIL(t->objName));
538 540 } else if (stat2 != 0) {
539 541 if (stat2 == EBUSY)
540 542 logmsg(MSG_NOTIMECHECK, LOG_INFO,
541 543 "%s: 'db_mindex' busy; no LDAP update for \"%s\"",
542 544 myself, NIL(t->objName));
543 545 else
544 546 logmsg(MSG_NOTIMECHECK, LOG_ERR,
545 547 "%s: 'db_mindex' lock error %d; no LDAP update for \"%s\"",
546 548 myself, stat2, NIL(t->objName));
547 549 } else {
548 550 if (stat3 == EBUSY)
549 551 logmsg(MSG_NOTIMECHECK, LOG_INFO,
550 552 "%s: 'db_table' busy; no LDAP update for \"%s\"",
551 553 myself, NIL(t->objName));
552 554 else
553 555 logmsg(MSG_NOTIMECHECK, LOG_ERR,
554 556 "%s: 'db_table' lock error %d; no LDAP update for \"%s\"",
555 557 myself, stat3, NIL(t->objName));
556 558 }
557 559 freeQueries(res, nq);
558 560 if (arg->isDeferred) {
559 561 dstat = InUseDictionary->rollback(t->objPath);
560 562 if (dstat != DB_SUCCESS) {
561 563 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
562 564 "%s: DB error %d rolling back \"%s\"",
563 565 myself, dstat, NIL(t->objName));
564 566 /*
565 567 * Had rollback succeeded, the 'table'
566 568 * would have disappeared. However, since
567 569 * rollback failed, we need to update the
568 570 * table->mapping.enum* fields.
569 571 */
570 572 (void) mutex_lock(&table->mapping.enumLock);
571 573 table->mapping.enumStat = LDAP_OPERATIONS_ERROR;
572 574 table->mapping.enumTid = 0;
573 575 (void) mutex_unlock(&table->mapping.enumLock);
574 576 }
575 577 }
576 578 if (stat == 0) {
577 579 if (stat2 == 0) {
578 580 WRITEUNLOCK2(mindex, ((db *)mindex->getDbPtr()),
579 581 LDAP_OPERATIONS_ERROR,
580 582 LDAP_OPERATIONS_ERROR,
581 583 "db_mindex::entriesFromLDAPreal wu",
582 584 "db_mindex::entriesFromLDAPreal wu db");
583 585 } else {
584 586 WRITEUNLOCK(((db *)mindex->getDbPtr()),
585 587 LDAP_OPERATIONS_ERROR,
586 588 "db_mindex::entriesFromLDAPreal wu db");
587 589 }
588 590 }
589 591 unlockTransLog(myself, 1);
590 592 return (LDAP_OPERATIONS_ERROR);
591 593 }
592 594
593 595 stat = LDAP_SUCCESS;
594 596 mindex->setNoWriteThrough();
595 597 mindex->setNoLDAPquery();
596 598 if (qin == 0) {
597 599 table->setEnumMode(0);
598 600 doEnum = TRUE;
599 601
600 602 /*
601 603 * If there is no non-indexed table mapping, we must filter
602 604 * the enum mode (i.e., deletion candidates) array to only
603 605 * contain those entries that match the indexes.
604 606 */
605 607 if (haveIndexedMapping(t)) {
606 608 entry_object **tea = table->gettab();
607 609 long i, ntea = table->getsize();
608 610
609 611
610 612 /*
611 613 * Walk through the entry array, and remove any enum
612 614 * array entry that _doesn't_ match the index(es).
613 615 */
614 616 for (i = 0; i < ntea; i++) {
615 617 db_query *q;
616 618 __nis_table_mapping_t **tp;
617 619 int numMatches;
618 620
619 621 if (tea[i] == 0)
620 622 continue;
621 623
622 624 q = pseudoEntryObj2Query(tea[i], 0, 0);
623 625 if (q == 0)
624 626 continue;
625 627
626 628 tp = selectTableMapping(t, q, 0, 0, dbId,
627 629 &numMatches);
628 630 if (tp == 0 || numMatches <= 0)
629 631 table->enumTouch(i);
630 632
631 633 sfree(tp);
632 634
633 635 freeQuery(q);
634 636 }
635 637 }
636 638
637 639 logmsg(MSG_NOTIMECHECK, LOG_INFO, "%s: %d entries from LDAP",
638 640 myself, nq);
639 641 } else {
640 642 db_index_entry *dbie;
641 643 long i, count;
642 644 bool_t valid;
643 645
644 646 /*
645 647 * Find the entries in the DB that currently match the
646 648 * query, and add them to the enum array. Those that
647 649 * remain untouched when we've processed the LDAP data
648 650 * don't currently exist in LDAP, and should be deleted
649 651 * from the DB.
650 652 */
651 653 dbie = mindex->satisfy_query_dbonly(qin, &count, FALSE, &valid);
652 654 if (dbie != 0 && valid && count > 0) {
653 655 table->setEnumMode(count);
654 656 doEnum = TRUE;
655 657 for (i = 0; i < count; i++) {
656 658 table->enumSetup(dbie->getlocation(), i);
657 659 dbie = dbie->getnextresult();
658 660 if (dbie == 0)
659 661 break;
660 662 }
661 663 } else {
662 664 doEnum = FALSE;
663 665 }
664 666 }
665 667
666 668 entry_col ec[NIS_MAXCOLUMNS+1];
667 669 for (i = 0, na = 0; i < nq; i++) {
668 670 entry_object eo, *e;
669 671 table_col *tc;
670 672 nis_object o, *to;
671 673 int j, nc;
672 674 db_qcomp *qc;
673 675
674 676 if (res[i] == 0)
675 677 continue;
676 678
677 679 #ifdef NISDB_LDAP_DEBUG
678 680 printQuery(res[i], t);
679 681 printObjAttr(oa[i]);
680 682 #endif /* NISDB_LDAP_DEBUG */
681 683
682 684 /* Assemble an object from the query and attributes */
683 685 (void) memset(&o, 0, sizeof (o));
684 686 if (oa[i] != 0) {
685 687 o.zo_owner = oa[i]->zo_owner;
686 688 o.zo_group = oa[i]->zo_group;
687 689 o.zo_domain = oa[i]->zo_domain;
688 690 o.zo_access = oa[i]->zo_access;
689 691 o.zo_ttl = oa[i]->zo_ttl;
690 692 }
691 693 if ((to = t->obj) != 0) {
692 694 o.zo_name = to->zo_name;
693 695 o.zo_data.objdata_u.en_data.en_type =
694 696 to->zo_data.objdata_u.ta_data.ta_type;
695 697 tc = to->zo_data.objdata_u.ta_data.ta_cols.ta_cols_val;
696 698 if (to->zo_data.objdata_u.ta_data.ta_cols.ta_cols_len
697 699 != t->numColumns)
698 700 tc = 0;
699 701 if (o.zo_owner == 0)
700 702 o.zo_owner = to->zo_owner;
701 703 if (o.zo_group == 0)
702 704 o.zo_group = to->zo_group;
703 705 if (o.zo_domain == 0)
704 706 o.zo_domain = to->zo_domain;
705 707 if (o.zo_access == 0)
706 708 o.zo_access = to->zo_access;
707 709 if (o.zo_ttl == 0)
708 710 o.zo_ttl = to->zo_ttl;
709 711 } else {
710 712 tc = 0;
711 713 o.zo_owner = (nis_name)"";
712 714 o.zo_group = (nis_name)"";
713 715 o.zo_domain = (nis_name)"";
714 716 }
715 717
716 718 o.zo_data.zo_type = NIS_ENTRY_OBJ;
717 719 o.zo_data.objdata_u.en_data.en_cols.en_cols_len =
718 720 t->numColumns + 1;
719 721 o.zo_data.objdata_u.en_data.en_cols.en_cols_val = ec;
720 722
721 723 (void) memset(&ec, 0, sizeof (ec));
722 724 nc = res[i]->size();
723 725 qc = res[i]->queryloc();
724 726 if (qc == 0) {
725 727 freeQuery(res[i]);
726 728 continue;
727 729 }
728 730 for (j = 0; j < nc; j++) {
729 731 int ic = 1+ qc[j].which_index;
730 732 if (ic < 1 || ic > t->numColumns)
731 733 continue;
732 734 #ifdef SET_ENTRY_FLAGS
733 735 if (tc != 0)
734 736 ec[ic].ec_flags =
735 737 entryFlagsFromTable(tc[ic-1].tc_flags);
736 738 #else
737 739 /*
738 740 * In theory, the entry flags should be derived
739 741 * from the table flags. However, that doesn't
740 742 * seem to be the way that the DB code has done
741 743 * things so far, so leave the entry flags unset.
742 744 */
743 745 #endif /* SET_ENTRY_FLAGS */
744 746 qc[j].index_value->get_value(
745 747 &ec[ic].ec_value.ec_value_val,
746 748 (int *)&ec[ic].ec_value.ec_value_len);
747 749 }
748 750
749 751 setOid(&o);
750 752 e = makePseudoEntryObj(&o, &eo, t->obj);
751 753 if (e == 0) {
752 754 freeQuery(res[i]);
753 755 continue;
754 756 }
755 757
756 758 /*
757 759 * 'o' is currently a pseudo-object of type entry, with
758 760 * column zero used for an XDR:ed version of the entry_obj,
759 761 * column one the real column zero of the entry, etc.
760 762 * We now need a real NIS_ENTRY_OBJ object, so move the
761 763 * entry_col array one step left.
762 764 */
763 765 o.zo_data.objdata_u.en_data.en_cols.en_cols_len = t->numColumns;
764 766 o.zo_data.objdata_u.en_data.en_cols.en_cols_val = &ec[1];
765 767
766 768 stat = mindex->updateTableEntry(e, 1, t->objName, &o, t->obj,
767 769 o.zo_oid.mtime, &xid);
768 770 /*
769 771 * LDAP_SUCCESS => Entry added or modified
770 772 * LDAP_COMPARE_TRUE => Entry same as existing one
771 773 * other => Error
772 774 */
773 775 if (stat == LDAP_SUCCESS) {
774 776 na++;
775 777 } else if (stat == LDAP_COMPARE_TRUE) {
776 778 stat = LDAP_SUCCESS;
777 779 } else {
778 780 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
779 781 "%s: Error adding entry to \"%s\": %s",
780 782 myself, NIL(t->objName),
781 783 ldap_err2string(stat));
782 784 }
783 785
784 786 if (e->en_cols.en_cols_val != 0)
785 787 sfree(e->en_cols.en_cols_val[0].ec_value.ec_value_val);
786 788
787 789 freeQuery(res[i]);
788 790 }
789 791
790 792 sfree(res);
791 793
792 794 /* Take care of deletes if we enumerated the table */
793 795 if (doEnum) {
794 796 ea = table->endEnumMode(&numEa);
795 797 logmsg(MSG_NOTIMECHECK, LOG_INFO,
796 798 "%s: %d entries added/updated", myself, na);
797 799 nau = na;
798 800 } else
799 801 ea = 0;
800 802 if (ea != 0) {
801 803 uint32_t nowt = time(0);
802 804
803 805 for (i = 0; i < numEa; i++) {
804 806 int st;
805 807
806 808 if (ea[i] == 0)
807 809 continue;
808 810
809 811 st = mindex->updateTableEntry(ea[i], 0, t->objName, 0,
810 812 t->obj, nowt, &xid);
811 813 if (st == LDAP_SUCCESS) {
812 814 na++;
813 815 } else {
814 816 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
815 817 "%s: Error removing directory entry for \"%s\": %s",
816 818 myself, NIL(t->objName),
817 819 ldap_err2string(st));
818 820 if (stat == LDAP_SUCCESS)
819 821 stat = st;
820 822 }
821 823 }
822 824 if (stat == LDAP_SUCCESS) {
823 825 struct timeval now;
824 826 (void) gettimeofday(&now, 0);
825 827 table->mapping.enumExpire = now.tv_sec +
826 828 table->mapping.ttl;
827 829 }
828 830 if (doEnum)
829 831 logmsg(MSG_NOTIMECHECK, LOG_INFO,
830 832 "%s: %d entries deleted", myself, na-nau);
831 833 }
832 834
833 835 sfree(ea);
834 836
835 837 /* If we called log_action() successfully, we need to sync the log */
836 838 if (na > 0)
837 839 (void) ((db *)mindex->getDbPtr())->sync_log();
838 840
839 841 if (xid != 0 && na > 0 && stat == LDAP_SUCCESS)
840 842 ret = endTransaction(xid, dirObj);
841 843 else if (xid != 0)
842 844 ret = abort_transaction(xid);
843 845 else
844 846 ret = 0;
845 847 if (ret != 0) {
846 848 logmsg(MSG_NOTIMECHECK, LOG_ERR,
847 849 "%s: Error %s transaction for \"%s\"",
848 850 myself, (na > 0 && stat == LDAP_SUCCESS) ?
849 851 "ending" : "aborting",
850 852 NIL(t->objName));
851 853 stat = LDAP_OPERATIONS_ERROR;
852 854 }
853 855
854 856 mindex->clearNoLDAPquery();
855 857 mindex->clearNoWriteThrough();
856 858 freeObjAttr(oa, nq);
857 859
858 860 #ifdef NISDB_LDAP_DEBUG
859 861 printbuf();
860 862 #endif /* NISDB_LDAP_DEBUG */
861 863
862 864 if (doEnum)
863 865 logmsg(MSG_NOTIMECHECK, LOG_INFO,
864 866 "%s: enumeration \"%s\" done", myself, NIL(t->objName));
865 867
866 868 if (arg->isDeferred) {
867 869 /*
868 870 * Rollback doesn't recover data written to disk, so
869 871 * we should commit even if we're returning failure.
870 872 */
871 873 dstat = InUseDictionary->commit(t->objPath);
872 874 if (dstat != DB_SUCCESS) {
873 875 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
874 876 "%s: DB error %d committing \"%s\"",
875 877 myself, dstat, NIL(t->objName));
876 878 }
877 879 }
878 880 (void) mutex_lock(&table->mapping.enumLock);
879 881 if (arg->isDeferred && dstat == DB_SUCCESS)
880 882 table->mapping.enumDeferred = 0;
881 883 table->mapping.enumStat = stat;
882 884 {
883 885 struct timeval end;
884 886
885 887 (void) gettimeofday(&end, 0);
886 888 end.tv_sec -= start.tv_sec;
887 889 end.tv_usec -= start.tv_usec;
888 890 if (end.tv_usec < 0) {
889 891 end.tv_usec += 1000000;
890 892 end.tv_sec -= 1;
891 893 }
892 894 table->mapping.enumTime = 1000000*end.tv_sec + end.tv_usec;
893 895 logmsg(MSG_NOTIMECHECK,
894 896 #ifdef NISDB_LDAP_DEBUG
895 897 LOG_WARNING,
896 898 #else
897 899 LOG_INFO,
898 900 #endif /* NISDB_LDAP_DEBUG */
899 901 "%s: %d entries in %ld usec => %ld usec/entry",
900 902 NIL(t->objName), table->mapping.enumEntries,
901 903 table->mapping.enumTime,
902 904 table->mapping.enumTime/
903 905 (table->mapping.enumEntries != 0 ?
904 906 table->mapping.enumEntries : 1));
905 907 }
906 908 table->mapping.enumTid = 0;
907 909 (void) mutex_unlock(&table->mapping.enumLock);
908 910
909 911 WRITEUNLOCKNR(table, stat3, "table wu db_mindex::entriesFromLDAPreal");
910 912 WRITEUNLOCKNR(mindex, stat2, "db_mindex::entriesFromLDAPreal wu");
911 913 WRITEUNLOCKNR(((db *)mindex->getDbPtr()), lstat,
912 914 "db db_mindex::entriesFromLDAPreal wu");
913 915 unlockTransLog(myself, 1);
914 916 if (stat3 != 0)
915 917 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
916 918 "%s: Error %d unlocking db_table", myself, stat3);
917 919 if (stat2 != 0)
918 920 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
919 921 "%s: Error %d unlocking db_mindex", myself, stat2);
920 922 if (lstat != 0)
921 923 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
922 924 "%s: Error %d unlocking db", myself, lstat);
923 925
924 926 return (stat);
925 927 }
926 928 /*
927 929 * Sets the oid (i.e., the creation and modification times) for the
928 930 * specified object. In order to avoid retrieving the old incarnation
929 931 * (if any) from the DB first, we're punting and setting both mtime
930 932 * and ctime to the current time.
931 933 */
932 934 static void
933 935 setOid(nis_object *obj) {
934 936 if (obj != 0) {
935 937 obj->zo_oid.ctime = obj->zo_oid.mtime = time(0);
936 938 }
937 939 }
↓ open down ↓ |
604 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX