~ttx/openldap/lucid-gssapi-495418

« back to all changes in this revision

Viewing changes to servers/slapd/alock.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug
  • Date: 2008-07-10 14:45:49 UTC
  • Revision ID: james.westby@ubuntu.com-20080710144549-wck73med0e72gfyo
Tags: upstream-2.4.10
ImportĀ upstreamĀ versionĀ 2.4.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* alock.c - access lock library */
 
2
/* $OpenLDAP: pkg/ldap/servers/slapd/alock.c,v 1.5.2.7 2008/02/11 23:26:43 kurt Exp $ */
 
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 
4
 *
 
5
 * Copyright 2005-2008 The OpenLDAP Foundation.
 
6
 * Portions Copyright 2004-2005 Symas Corporation.
 
7
 * All rights reserved.
 
8
 *
 
9
 * Redistribution and use in source and binary forms, with or without
 
10
 * modification, are permitted only as authorized by the OpenLDAP
 
11
 * Public License.
 
12
 *
 
13
 * A copy of this license is available in the file LICENSE in the
 
14
 * top-level directory of the distribution or, alternatively, at
 
15
 * <http://www.OpenLDAP.org/license.html>.
 
16
 */
 
17
/* ACKNOWLEDGEMENTS:
 
18
 * This work was initially developed by Matthew Backes at Symas
 
19
 * Corporation for inclusion in OpenLDAP Software.
 
20
 */
 
21
 
 
22
#include "portable.h"
 
23
 
 
24
#if SLAPD_BDB || SLAPD_HDB
 
25
 
 
26
#include "alock.h"
 
27
 
 
28
#include <ac/stdlib.h>
 
29
#include <ac/string.h>
 
30
#include <ac/unistd.h>
 
31
#include <ac/errno.h>
 
32
#include <ac/assert.h>
 
33
#include <sys/types.h>
 
34
#include <sys/stat.h>
 
35
#ifdef HAVE_SYS_FILE_H
 
36
#include <sys/file.h>
 
37
#endif
 
38
#include <fcntl.h>
 
39
 
 
40
#ifdef _WIN32
 
41
#include <stdio.h>
 
42
#include <io.h>
 
43
#include <sys/locking.h>
 
44
#endif
 
45
 
 
46
 
 
47
static int
 
48
alock_grab_lock ( int fd, int slot )
 
49
{
 
50
        int res;
 
51
        
 
52
#if defined( HAVE_LOCKF )
 
53
        res = lseek (fd, (off_t) (ALOCK_SLOT_SIZE * slot), SEEK_SET);
 
54
        if (res == -1) return -1;
 
55
        res = lockf (fd, F_LOCK, (off_t) ALOCK_SLOT_SIZE);
 
56
#elif defined( HAVE_FCNTL )
 
57
        struct flock lock_info;
 
58
        (void) memset ((void *) &lock_info, 0, sizeof (struct flock));
 
59
 
 
60
        lock_info.l_type = F_WRLCK;
 
61
        lock_info.l_whence = SEEK_SET;
 
62
        lock_info.l_start = (off_t) (ALOCK_SLOT_SIZE * slot);
 
63
        lock_info.l_len = (off_t) ALOCK_SLOT_SIZE;
 
64
 
 
65
        res = fcntl (fd, F_SETLKW, &lock_info);
 
66
#elif defined( _WIN32 )
 
67
        if( _lseek( fd, (ALOCK_SLOT_SIZE * slot), SEEK_SET ) < 0 )
 
68
                return -1;
 
69
        /*
 
70
         * _lock will try for the lock once per second, returning EDEADLOCK
 
71
         * after ten tries. We just loop until we either get the lock
 
72
         * or some other error is returned.
 
73
         */
 
74
        while((res = _locking( fd, _LK_LOCK, ALOCK_SLOT_SIZE )) < 0 ) {
 
75
                if( errno != EDEADLOCK )
 
76
                        break;
 
77
        }
 
78
#else
 
79
#   error alock needs lockf, fcntl, or _locking
 
80
#endif
 
81
        if (res == -1) {
 
82
                assert (errno != EDEADLK);
 
83
                return -1;
 
84
        }
 
85
        return 0;
 
86
}
 
87
 
 
88
static int
 
89
alock_release_lock ( int fd, int slot )
 
90
{
 
91
        int res;
 
92
        
 
93
#if defined( HAVE_LOCKF )
 
94
        res = lseek (fd, (off_t) (ALOCK_SLOT_SIZE * slot), SEEK_SET);
 
95
        if (res == -1) return -1;
 
96
        res = lockf (fd, F_ULOCK, (off_t) ALOCK_SLOT_SIZE);
 
97
        if (res == -1) return -1;
 
98
#elif defined ( HAVE_FCNTL )
 
99
        struct flock lock_info;
 
100
        (void) memset ((void *) &lock_info, 0, sizeof (struct flock));
 
101
 
 
102
        lock_info.l_type = F_UNLCK;
 
103
        lock_info.l_whence = SEEK_SET;
 
104
        lock_info.l_start = (off_t) (ALOCK_SLOT_SIZE * slot);
 
105
        lock_info.l_len = (off_t) ALOCK_SLOT_SIZE;
 
106
 
 
107
        res = fcntl (fd, F_SETLKW, &lock_info);
 
108
        if (res == -1) return -1;
 
109
#elif defined( _WIN32 )
 
110
        res = _lseek (fd, (ALOCK_SLOT_SIZE * slot), SEEK_SET);
 
111
        if (res == -1) return -1;
 
112
        res = _locking( fd, _LK_UNLCK, ALOCK_SLOT_SIZE );
 
113
        if (res == -1) return -1;
 
114
#else
 
115
#   error alock needs lockf, fcntl, or _locking
 
116
#endif
 
117
 
 
118
        return 0;
 
119
}
 
120
 
 
121
static int
 
122
alock_test_lock ( int fd, int slot )
 
123
{
 
124
        int res;
 
125
 
 
126
#if defined( HAVE_LOCKF )
 
127
        res = lseek (fd, (off_t) (ALOCK_SLOT_SIZE * slot), SEEK_SET);
 
128
        if (res == -1) return -1;
 
129
 
 
130
        res = lockf (fd, F_TEST, (off_t) ALOCK_SLOT_SIZE);
 
131
        if (res == -1) {
 
132
                if (errno == EACCES || errno == EAGAIN) { 
 
133
                        return ALOCK_LOCKED;
 
134
                } else {
 
135
                        return -1;
 
136
                }
 
137
        }
 
138
#elif defined( HAVE_FCNTL )
 
139
        struct flock lock_info;
 
140
        (void) memset ((void *) &lock_info, 0, sizeof (struct flock));
 
141
 
 
142
        lock_info.l_type = F_WRLCK;
 
143
        lock_info.l_whence = SEEK_SET;
 
144
        lock_info.l_start = (off_t) (ALOCK_SLOT_SIZE * slot);
 
145
        lock_info.l_len = (off_t) ALOCK_SLOT_SIZE;
 
146
 
 
147
        res = fcntl (fd, F_GETLK, &lock_info);
 
148
        if (res == -1) return -1;
 
149
 
 
150
        if (lock_info.l_type != F_UNLCK) return ALOCK_LOCKED;
 
151
#elif defined( _WIN32 )
 
152
        res = _lseek (fd, (ALOCK_SLOT_SIZE * slot), SEEK_SET);
 
153
        if (res == -1) return -1;
 
154
        res = _locking( fd, _LK_NBLCK, ALOCK_SLOT_SIZE );
 
155
        _locking( fd, _LK_UNLCK, ALOCK_SLOT_SIZE );
 
156
        if (res == -1) {
 
157
           if( errno == EACCES ) {
 
158
                   return ALOCK_LOCKED;
 
159
           } else {
 
160
                   return -1;
 
161
           }
 
162
        }
 
163
#else
 
164
#   error alock needs lockf, fcntl, or _locking
 
165
#endif
 
166
        
 
167
        return 0;
 
168
}
 
169
 
 
170
/* Read a 64bit LE value */
 
171
static unsigned long int
 
172
alock_read_iattr ( unsigned char * bufptr )
 
173
{
 
174
        unsigned long int val = 0;
 
175
        int count;
 
176
 
 
177
        assert (bufptr != NULL);
 
178
 
 
179
        bufptr += sizeof (unsigned long int);
 
180
        for (count=0; count <= sizeof (unsigned long int); ++count) {
 
181
                val <<= 8;
 
182
                val += (unsigned long int) *bufptr--;
 
183
        }
 
184
 
 
185
        return val;
 
186
}
 
187
 
 
188
/* Write a 64bit LE value */
 
189
static void
 
190
alock_write_iattr ( unsigned char * bufptr,
 
191
                    unsigned long int val )
 
192
{
 
193
        int count;
 
194
 
 
195
        assert (bufptr != NULL);
 
196
 
 
197
        for (count=0; count < 8; ++count) {
 
198
                *bufptr++ = (unsigned char) (val & 0xff);
 
199
                val >>= 8;
 
200
        }
 
201
}
 
202
 
 
203
static int
 
204
alock_read_slot ( alock_info_t * info,
 
205
                  alock_slot_t * slot_data )
 
206
{
 
207
        unsigned char slotbuf [ALOCK_SLOT_SIZE];
 
208
        int res, size, size_total, err;
 
209
 
 
210
        assert (info != NULL);
 
211
        assert (slot_data != NULL);
 
212
        assert (info->al_slot > 0);
 
213
 
 
214
        res = lseek (info->al_fd, 
 
215
                     (off_t) (ALOCK_SLOT_SIZE * info->al_slot), 
 
216
                     SEEK_SET);
 
217
        if (res == -1) return -1;
 
218
 
 
219
        size_total = 0;
 
220
        while (size_total < ALOCK_SLOT_SIZE) {
 
221
                size = read (info->al_fd, 
 
222
                             slotbuf + size_total, 
 
223
                             ALOCK_SLOT_SIZE - size_total);
 
224
                if (size == 0) return -1;
 
225
                if (size < 0) {
 
226
                        err = errno;
 
227
                        if (err != EINTR && err != EAGAIN) return -1;
 
228
                } else {
 
229
                        size_total += size;
 
230
                }
 
231
        }
 
232
        
 
233
        if (alock_read_iattr (slotbuf) != ALOCK_MAGIC) {
 
234
                return -1;
 
235
        }
 
236
        slot_data->al_lock  = alock_read_iattr (slotbuf+8);
 
237
        slot_data->al_stamp = alock_read_iattr (slotbuf+16);
 
238
        slot_data->al_pid   = alock_read_iattr (slotbuf+24);
 
239
 
 
240
        if (slot_data->al_appname) free (slot_data->al_appname);
 
241
        slot_data->al_appname = calloc (1, ALOCK_MAX_APPNAME);
 
242
        strncpy (slot_data->al_appname, (char *)slotbuf+32, ALOCK_MAX_APPNAME-1);
 
243
        (slot_data->al_appname) [ALOCK_MAX_APPNAME-1] = '\0';
 
244
 
 
245
        return 0;
 
246
}
 
247
 
 
248
static int
 
249
alock_write_slot ( alock_info_t * info,
 
250
                   alock_slot_t * slot_data )
 
251
{
 
252
        unsigned char slotbuf [ALOCK_SLOT_SIZE];
 
253
        int res, size, size_total, err;
 
254
 
 
255
        assert (info != NULL);
 
256
        assert (slot_data != NULL);
 
257
        assert (info->al_slot > 0);
 
258
 
 
259
        (void) memset ((void *) slotbuf, 0, ALOCK_SLOT_SIZE);
 
260
        
 
261
        alock_write_iattr (slotbuf,    ALOCK_MAGIC);
 
262
        assert (alock_read_iattr (slotbuf) == ALOCK_MAGIC);
 
263
        alock_write_iattr (slotbuf+8,  slot_data->al_lock);
 
264
        alock_write_iattr (slotbuf+16, slot_data->al_stamp);
 
265
        alock_write_iattr (slotbuf+24, slot_data->al_pid);
 
266
 
 
267
        if (slot_data->al_appname)
 
268
                strncpy ((char *)slotbuf+32, slot_data->al_appname, ALOCK_MAX_APPNAME-1);
 
269
        slotbuf[ALOCK_SLOT_SIZE-1] = '\0';
 
270
 
 
271
        res = lseek (info->al_fd, 
 
272
                     (off_t) (ALOCK_SLOT_SIZE * info->al_slot),
 
273
                     SEEK_SET);
 
274
        if (res == -1) return -1;
 
275
 
 
276
        size_total = 0;
 
277
        while (size_total < ALOCK_SLOT_SIZE) {
 
278
                size = write (info->al_fd, 
 
279
                              slotbuf + size_total, 
 
280
                              ALOCK_SLOT_SIZE - size_total);
 
281
                if (size == 0) return -1;
 
282
                if (size < 0) {
 
283
                        err = errno;
 
284
                        if (err != EINTR && err != EAGAIN) return -1;
 
285
                } else {
 
286
                        size_total += size;
 
287
                }
 
288
        }
 
289
        
 
290
        return 0;
 
291
}
 
292
 
 
293
static int
 
294
alock_query_slot ( alock_info_t * info )
 
295
{
 
296
        int res, nosave;
 
297
        alock_slot_t slot_data;
 
298
 
 
299
        assert (info != NULL);
 
300
        assert (info->al_slot > 0);
 
301
        
 
302
        (void) memset ((void *) &slot_data, 0, sizeof (alock_slot_t));
 
303
        alock_read_slot (info, &slot_data);
 
304
 
 
305
        if (slot_data.al_appname != NULL) free (slot_data.al_appname);
 
306
        slot_data.al_appname = NULL;
 
307
 
 
308
        nosave = slot_data.al_lock & ALOCK_NOSAVE;
 
309
 
 
310
        if ((slot_data.al_lock & ALOCK_SMASK) == ALOCK_UNLOCKED)
 
311
                return slot_data.al_lock;
 
312
 
 
313
        res = alock_test_lock (info->al_fd, info->al_slot);
 
314
        if (res < 0) return -1;
 
315
        if (res > 0) {
 
316
                if ((slot_data.al_lock & ALOCK_SMASK) == ALOCK_UNIQUE) {
 
317
                        return slot_data.al_lock;
 
318
                } else {
 
319
                        return ALOCK_LOCKED | nosave;
 
320
                }
 
321
        }
 
322
        
 
323
        return ALOCK_DIRTY | nosave;
 
324
}
 
325
 
 
326
int 
 
327
alock_open ( alock_info_t * info,
 
328
             const char * appname,
 
329
             const char * envdir,
 
330
             int locktype )
 
331
{
 
332
        struct stat statbuf;
 
333
        alock_info_t scan_info;
 
334
        alock_slot_t slot_data;
 
335
        char * filename;
 
336
        int res, max_slot;
 
337
        int dirty_count, live_count, nosave;
 
338
 
 
339
        assert (info != NULL);
 
340
        assert (appname != NULL);
 
341
        assert (envdir != NULL);
 
342
        assert ((locktype & ALOCK_SMASK) >= 1 && (locktype & ALOCK_SMASK) <= 2);
 
343
 
 
344
        slot_data.al_lock = locktype;
 
345
        slot_data.al_stamp = time(NULL);
 
346
        slot_data.al_pid = getpid();
 
347
        slot_data.al_appname = calloc (1, ALOCK_MAX_APPNAME);
 
348
        strncpy (slot_data.al_appname, appname, ALOCK_MAX_APPNAME-1);
 
349
        slot_data.al_appname [ALOCK_MAX_APPNAME-1] = '\0';
 
350
 
 
351
        filename = calloc (1, strlen (envdir) + strlen ("/alock") + 1);
 
352
        strcpy (filename, envdir);
 
353
        strcat (filename, "/alock");
 
354
        info->al_fd = open (filename, O_CREAT|O_RDWR, 0666);
 
355
        free (filename);
 
356
        if (info->al_fd < 0) {
 
357
                free (slot_data.al_appname);
 
358
                return ALOCK_UNSTABLE;
 
359
        }
 
360
        info->al_slot = 0;
 
361
 
 
362
        res = alock_grab_lock (info->al_fd, 0);
 
363
        if (res == -1) { 
 
364
                close (info->al_fd);
 
365
                free (slot_data.al_appname);
 
366
                return ALOCK_UNSTABLE;
 
367
        }
 
368
 
 
369
        res = fstat (info->al_fd, &statbuf);
 
370
        if (res == -1) { 
 
371
                close (info->al_fd);
 
372
                free (slot_data.al_appname);
 
373
                return ALOCK_UNSTABLE;
 
374
        }
 
375
 
 
376
        max_slot = (statbuf.st_size + ALOCK_SLOT_SIZE - 1) / ALOCK_SLOT_SIZE;
 
377
        dirty_count = 0;
 
378
        live_count = 0;
 
379
        nosave = 0;
 
380
        scan_info.al_fd = info->al_fd;
 
381
        for (scan_info.al_slot = 1; 
 
382
             scan_info.al_slot < max_slot;
 
383
             ++ scan_info.al_slot) {
 
384
                if (scan_info.al_slot != info->al_slot) {
 
385
                        res = alock_query_slot (&scan_info);
 
386
 
 
387
                        if (res & ALOCK_NOSAVE) {
 
388
                                nosave = ALOCK_NOSAVE;
 
389
                                res ^= ALOCK_NOSAVE;
 
390
                        }
 
391
                        if (res == ALOCK_UNLOCKED
 
392
                            && info->al_slot == 0) {
 
393
                                info->al_slot = scan_info.al_slot;
 
394
 
 
395
                        } else if (res == ALOCK_LOCKED) {
 
396
                                ++live_count;
 
397
 
 
398
                        } else if (res == ALOCK_UNIQUE
 
399
                                && locktype == ALOCK_UNIQUE) {
 
400
                                close (info->al_fd);
 
401
                                free (slot_data.al_appname);
 
402
                                return ALOCK_BUSY;
 
403
 
 
404
                        } else if (res == ALOCK_DIRTY) {
 
405
                                ++dirty_count;
 
406
 
 
407
                        } else if (res == -1) {
 
408
                                close (info->al_fd);
 
409
                                free (slot_data.al_appname);
 
410
                                return ALOCK_UNSTABLE;
 
411
 
 
412
                        }
 
413
                }
 
414
        }
 
415
 
 
416
        if (dirty_count && live_count) {
 
417
                close (info->al_fd);
 
418
                free (slot_data.al_appname);
 
419
                return ALOCK_UNSTABLE;
 
420
        }
 
421
        
 
422
        if (info->al_slot == 0) info->al_slot = max_slot + 1;
 
423
        res = alock_grab_lock (info->al_fd,
 
424
                               info->al_slot);
 
425
        if (res == -1) { 
 
426
                close (info->al_fd);
 
427
                free (slot_data.al_appname);
 
428
                return ALOCK_UNSTABLE;
 
429
        }
 
430
        res = alock_write_slot (info, &slot_data);
 
431
        free (slot_data.al_appname);
 
432
        if (res == -1) { 
 
433
                close (info->al_fd);
 
434
                return ALOCK_UNSTABLE;
 
435
        }
 
436
 
 
437
        res = alock_release_lock (info->al_fd, 0);
 
438
        if (res == -1) { 
 
439
                close (info->al_fd);
 
440
                return ALOCK_UNSTABLE;
 
441
        }
 
442
        
 
443
        if (dirty_count) return ALOCK_RECOVER | nosave;
 
444
        return ALOCK_CLEAN | nosave;
 
445
}
 
446
 
 
447
int 
 
448
alock_scan ( alock_info_t * info )
 
449
{
 
450
        struct stat statbuf;
 
451
        alock_info_t scan_info;
 
452
        int res, max_slot;
 
453
        int dirty_count, live_count, nosave;
 
454
 
 
455
        assert (info != NULL);
 
456
 
 
457
        scan_info.al_fd = info->al_fd;
 
458
 
 
459
        res = alock_grab_lock (info->al_fd, 0);
 
460
        if (res == -1) {
 
461
                close (info->al_fd);
 
462
                return ALOCK_UNSTABLE;
 
463
        }
 
464
 
 
465
        res = fstat (info->al_fd, &statbuf);
 
466
        if (res == -1) {
 
467
                close (info->al_fd);
 
468
                return ALOCK_UNSTABLE;
 
469
        }
 
470
 
 
471
        max_slot = (statbuf.st_size + ALOCK_SLOT_SIZE - 1) / ALOCK_SLOT_SIZE;
 
472
        dirty_count = 0;
 
473
        live_count = 0;
 
474
        nosave = 0;
 
475
        for (scan_info.al_slot = 1; 
 
476
             scan_info.al_slot < max_slot;
 
477
             ++ scan_info.al_slot) {
 
478
                if (scan_info.al_slot != info->al_slot) {
 
479
                        res = alock_query_slot (&scan_info);
 
480
 
 
481
                        if (res & ALOCK_NOSAVE) {
 
482
                                nosave = ALOCK_NOSAVE;
 
483
                                res ^= ALOCK_NOSAVE;
 
484
                        }
 
485
 
 
486
                        if (res == ALOCK_LOCKED) {
 
487
                                ++live_count;
 
488
                                
 
489
                        } else if (res == ALOCK_DIRTY) {
 
490
                                ++dirty_count;
 
491
 
 
492
                        } else if (res == -1) {
 
493
                                close (info->al_fd);
 
494
                                return ALOCK_UNSTABLE;
 
495
 
 
496
                        }
 
497
                }
 
498
        }
 
499
 
 
500
        res = alock_release_lock (info->al_fd, 0);
 
501
        if (res == -1) {
 
502
                close (info->al_fd);
 
503
                return ALOCK_UNSTABLE;
 
504
        }
 
505
 
 
506
        if (dirty_count) {
 
507
                if (live_count) {
 
508
                        close (info->al_fd);
 
509
                        return ALOCK_UNSTABLE;
 
510
                } else {
 
511
                        return ALOCK_RECOVER | nosave;
 
512
                }
 
513
        }
 
514
        
 
515
        return ALOCK_CLEAN | nosave;
 
516
}
 
517
 
 
518
int
 
519
alock_close ( alock_info_t * info, int nosave )
 
520
{
 
521
        alock_slot_t slot_data;
 
522
        int res;
 
523
 
 
524
        if ( !info->al_slot )
 
525
                return ALOCK_CLEAN;
 
526
 
 
527
        (void) memset ((void *) &slot_data, 0, sizeof(alock_slot_t));
 
528
 
 
529
        res = alock_grab_lock (info->al_fd, 0);
 
530
        if (res == -1) {
 
531
                close (info->al_fd);
 
532
                return ALOCK_UNSTABLE;
 
533
        }
 
534
 
 
535
        /* mark our slot as clean */
 
536
        res = alock_read_slot (info, &slot_data);
 
537
        if (res == -1) {
 
538
                close (info->al_fd);
 
539
                if (slot_data.al_appname != NULL) 
 
540
                        free (slot_data.al_appname);
 
541
                return ALOCK_UNSTABLE;
 
542
        }
 
543
        slot_data.al_lock = ALOCK_UNLOCKED;
 
544
        if ( nosave )
 
545
                slot_data.al_lock |= ALOCK_NOSAVE;
 
546
        res = alock_write_slot (info, &slot_data);
 
547
        if (res == -1) {
 
548
                close (info->al_fd);
 
549
                if (slot_data.al_appname != NULL) 
 
550
                        free (slot_data.al_appname);
 
551
                return ALOCK_UNSTABLE;
 
552
        }
 
553
        if (slot_data.al_appname != NULL) {
 
554
                free (slot_data.al_appname);
 
555
                slot_data.al_appname = NULL;
 
556
        }
 
557
 
 
558
        res = alock_release_lock (info->al_fd, info->al_slot);
 
559
        if (res == -1) {
 
560
                close (info->al_fd);
 
561
                return ALOCK_UNSTABLE;
 
562
        }
 
563
        res = alock_release_lock (info->al_fd, 0);
 
564
        if (res == -1) {
 
565
                close (info->al_fd);
 
566
                return ALOCK_UNSTABLE;
 
567
        }
 
568
 
 
569
        res = close (info->al_fd);
 
570
        if (res == -1) return ALOCK_UNSTABLE;
 
571
        
 
572
        return ALOCK_CLEAN;
 
573
}
 
574
 
 
575
int 
 
576
alock_recover ( alock_info_t * info )
 
577
{
 
578
        struct stat statbuf;
 
579
        alock_slot_t slot_data;
 
580
        alock_info_t scan_info;
 
581
        int res, max_slot;
 
582
 
 
583
        assert (info != NULL);
 
584
 
 
585
        scan_info.al_fd = info->al_fd;
 
586
 
 
587
        (void) memset ((void *) &slot_data, 0, sizeof(alock_slot_t));
 
588
 
 
589
        res = alock_grab_lock (info->al_fd, 0);
 
590
        if (res == -1) {
 
591
                close (info->al_fd);
 
592
                return ALOCK_UNSTABLE;
 
593
        }
 
594
 
 
595
        res = fstat (info->al_fd, &statbuf);
 
596
        if (res == -1) {
 
597
                close (info->al_fd);
 
598
                return ALOCK_UNSTABLE;
 
599
        }
 
600
 
 
601
        max_slot = (statbuf.st_size + ALOCK_SLOT_SIZE - 1) / ALOCK_SLOT_SIZE;
 
602
        for (scan_info.al_slot = 1; 
 
603
             scan_info.al_slot < max_slot;
 
604
             ++ scan_info.al_slot) {
 
605
                if (scan_info.al_slot != info->al_slot) {
 
606
                        res = alock_query_slot (&scan_info) & ~ALOCK_NOSAVE;
 
607
 
 
608
                        if (res == ALOCK_LOCKED
 
609
                            || res == ALOCK_UNIQUE) {
 
610
                                /* recovery attempt on an active db? */
 
611
                                close (info->al_fd);
 
612
                                return ALOCK_UNSTABLE;
 
613
                                
 
614
                        } else if (res == ALOCK_DIRTY) {
 
615
                                /* mark it clean */
 
616
                                res = alock_read_slot (&scan_info, &slot_data);
 
617
                                if (res == -1) {
 
618
                                        close (info->al_fd);
 
619
                                        return ALOCK_UNSTABLE;
 
620
                                }
 
621
                                slot_data.al_lock = ALOCK_UNLOCKED;
 
622
                                res = alock_write_slot (&scan_info, &slot_data);
 
623
                                if (res == -1) {
 
624
                                        close (info->al_fd);
 
625
                                        if (slot_data.al_appname != NULL) 
 
626
                                                free (slot_data.al_appname);
 
627
                                        return ALOCK_UNSTABLE;
 
628
                                }
 
629
                                if (slot_data.al_appname != NULL) {
 
630
                                        free (slot_data.al_appname);
 
631
                                        slot_data.al_appname = NULL;
 
632
                                }
 
633
                                
 
634
                        } else if (res == -1) {
 
635
                                close (info->al_fd);
 
636
                                return ALOCK_UNSTABLE;
 
637
 
 
638
                        }
 
639
                }
 
640
        }
 
641
 
 
642
        res = alock_release_lock (info->al_fd, 0);
 
643
        if (res == -1) {
 
644
                close (info->al_fd);
 
645
                return ALOCK_UNSTABLE;
 
646
        }
 
647
 
 
648
        return ALOCK_CLEAN;
 
649
}
 
650
 
 
651
#endif /* SLAPD_BDB || SLAPD_HDB */