8354 sync regcomp(3C) with upstream (fix make catalog)
[unleashed/tickless.git] / usr / src / cmd / ypcmd / shared / lockmap.c
blob17cbe9e6d0a117e87805ec033c5a2599e8f2db14
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <unistd.h>
30 #include <syslog.h>
31 #include <sys/mman.h>
32 #include <thread.h>
33 #include <synch.h>
34 #include <strings.h>
35 #include <ndbm.h>
36 #include "../ypsym.h"
37 #include "../ypdefs.h"
38 #include "shim.h"
41 * These routines provide mutual exclusion between ypserv and ypxfr.
42 * Mutual exclusion is needed so that ypxfr doesn't try to rename
43 * dbm files while ypserv is trying to open them. After ypserv has
44 * opened a dbm file, it is safe to rename it because ypserv still
45 * has access to the file through its file descriptor.
48 #define LOCKFILE "/var/run/yp_maplock"
49 struct lockarray {
50 mutex_t locknode[MAXHASH];
52 typedef struct lockarray lockarray;
55 * Cross-process robust mutex locks.
56 * Provide synchronization between YP processes
57 * by implementing an exclusive locking mechanism
58 * via a memory-mapped file.
60 static struct lockarray *shmlockarray;
61 static int lockfile;
64 * Hash functions, used for by the locking mechanism.
66 * - hash() is the front-end function that gets called.
67 * - get_map_id() returns a unique int value per map.
68 * It is used in N2L mode only.
69 * It is called by hash() in N2L mode.
71 int
72 get_map_id(char *map_name, int index)
74 map_id_elt_t *cur_elt;
76 * Local references to hash table for map lists
77 * and to max number of maps
79 map_id_elt_t **map_list_p;
80 int max_map;
82 /* initializes map_list_p & max_map */
83 get_list_max(&map_list_p, &max_map);
85 cur_elt = map_list_p[index];
86 while (cur_elt != NULL) {
87 if (strcmp(map_name, cur_elt->map_name) == 0) {
88 /* found */
89 return (cur_elt->map_id);
91 cur_elt = cur_elt->next;
93 syslog(LOG_WARNING, "get_map_id: no hash id found for %s"
94 ", giving max_map value (%d)",
95 map_name, max_map);
97 * max_map does not match any map id, hence
98 * will not trigger any lock collision
99 * with existing maps.
100 * Needed for yp regular locking mechanism.
102 return (max_map);
106 hash(char *s)
108 unsigned int n = 0;
109 int i;
110 char *map_name = s;
112 for (i = 1; *s; i += 10, s++) {
113 n += i * (*s);
115 n %= MAXHASH;
117 if (yptol_mode & yptol_newlock) {
118 return (get_map_id(map_name, n));
119 } else {
120 return (n);
124 bool
125 init_locks_mem()
127 int iiter, rc;
128 int ebusy_cnt = 0;
131 * Initialize cross-process locks in memory-mapped file.
133 for (iiter = 0; iiter < MAXHASH; iiter++) {
134 if (rc = mutex_init(&(shmlockarray->locknode[iiter]),
135 USYNC_PROCESS | LOCK_ROBUST, 0)) {
136 if (rc == EBUSY) {
137 ebusy_cnt++;
138 } else {
139 syslog(LOG_ERR,
140 "init_locks_mem():mutex_init():error=%d",
141 rc);
142 return (FALSE);
148 * EBUSY for all locks OK, it means another process
149 * has already initialized locks.
151 if ((ebusy_cnt > 0) && (ebusy_cnt != MAXHASH)) {
152 syslog(LOG_ERR,
153 "%s inconsistent. Remove and restart NIS (YP).", LOCKFILE);
154 return (FALSE);
156 return (TRUE);
159 bool
160 init_lock_map()
162 char buff[ sizeof (lockarray) ];
163 int write_cnt, lf_size;
164 struct stat fdata;
167 * Locking file initialization algorithm, with recovery mechanism.
168 * This mechanism has been devised to ensure proper creation
169 * of a memory-mapped lock file containing mutexes for robust,
170 * inter-process communication.
171 * File name is /var/run/yp_maplock (LOCKFILE). It might or might
172 * not exist.
174 * Algorithm:
175 * Try to open the file. If file doesn't exist, or size is too small,
176 * create/rewrite the file, m-map it into memory and initialize the
177 * mutexes in it.
178 * If file exists and size is at least large enough, assume it's a
179 * good file, and m-map the lock structure directly to it.
181 * Recovery from inconsistent state is easy - simply delete the file
182 * and restart NIS (YP).
185 lockfile = open(LOCKFILE, O_RDWR|O_CREAT, 0600);
186 if (lockfile != -1) {
187 if (lockf(lockfile, F_LOCK, 0) == 0) {
188 if (fstat(lockfile, &fdata) == 0) {
189 lf_size = fdata.st_size;
190 if (lf_size < sizeof (lockarray)) {
191 bzero(buff, sizeof (buff));
192 if ((write_cnt = write(lockfile, buff,
193 sizeof (buff)) != sizeof (buff))) {
194 if (write_cnt < 0) {
195 syslog(LOG_ERR,
196 "write(%s) => errno=%d",
197 LOCKFILE, errno);
198 } else {
199 syslog(LOG_ERR,
200 "write(%s) => %d!=%d: wrong number of bytes written.",
201 LOCKFILE,
202 write_cnt,
203 sizeof (buff));
205 lockf(lockfile, F_ULOCK, 0);
206 close(lockfile);
207 return (FALSE);
210 } else {
211 syslog(LOG_ERR,
212 "fstat(%s) => errno=%d", LOCKFILE, errno);
213 lockf(lockfile, F_ULOCK, 0);
214 close(lockfile);
215 return (FALSE);
217 } else {
218 syslog(LOG_ERR,
219 "lockf(%s,F_LOCK) => errno=%d", LOCKFILE, errno);
220 close(lockfile);
221 return (FALSE);
223 } else {
224 syslog(LOG_ERR,
225 "open(%s) => errno=%d", LOCKFILE, errno);
226 return (FALSE);
230 * File exists with correct size, is open, and we're holding
231 * the file lock.
233 shmlockarray = (lockarray *)mmap((caddr_t)0, sizeof (lockarray),
234 PROT_READ | PROT_WRITE, MAP_SHARED, lockfile, 0);
235 if (shmlockarray == MAP_FAILED) {
236 syslog(LOG_ERR, "mmap(%s) => errno=%d", LOCKFILE, errno);
237 lockf(lockfile, F_ULOCK, 0);
238 close(lockfile);
239 return (FALSE);
243 * If we wrote zeroes to the file, we also need to initialize
244 * the mutex locks.
246 if (lf_size < sizeof (lockarray)) {
247 if (init_locks_mem() == FALSE) {
248 lockf(lockfile, F_ULOCK, 0);
249 close(lockfile);
250 if (remove(LOCKFILE) != 0) {
251 syslog(LOG_ERR,
252 "remove(%s) => errno=%d: Please delete file.",
253 LOCKFILE, errno);
255 return (FALSE);
259 if (lockf(lockfile, F_ULOCK, 0) != 0) {
260 syslog(LOG_ERR,
261 "lockf(%s,F_ULOCK) => errno=%d",
262 LOCKFILE, errno);
263 close(lockfile);
264 return (FALSE);
267 if (close(lockfile) == 0) {
268 return (TRUE);
269 } else {
270 syslog(LOG_ERR,
271 "close(%s) => errno=%d", LOCKFILE, errno);
272 return (FALSE);
277 * FUNCTION : lock_map()
279 * DESCRIPTION: Front end to the lock routine taking map name as argument.
281 * GIVEN : Map name.
283 * RETURNS : Same as lock_core
286 lock_map(char *mapname)
288 int hashval;
290 hashval = hash(mapname);
292 return (lock_core(hashval));
296 * FUNCTION : lock_core()
298 * DESCRIPTION: The core map locking function
300 * GIVEN : Map hash value
302 * RETURNS : 0 = Failure
303 * 1 = Success
306 lock_core(int hashval)
308 int rc;
311 * Robust, cross-process lock implementation
313 rc = mutex_lock(&(shmlockarray->locknode[hashval]));
314 while (rc != 0) {
315 switch (rc) {
316 case EOWNERDEAD:
318 * Previous lock owner died, resetting lock
319 * to recover from error.
321 rc = mutex_consistent(
322 &(shmlockarray->locknode[hashval]));
323 if (rc != 0) {
324 syslog(LOG_ERR,
325 "mutex_consistent(): error=%d", rc);
326 return (0);
328 rc = mutex_unlock(&(shmlockarray->locknode[hashval]));
329 if (rc != 0) {
330 syslog(LOG_ERR,
331 "mutex_unlock(): error=%d", rc);
332 return (0);
334 break;
335 default:
337 * Unrecoverable problem - nothing to do
338 * but exit YP and delete lock file.
340 syslog(LOG_ERR,
341 "mutex_lock(): error=%d", rc);
342 syslog(LOG_ERR,
343 "Please restart NIS (ypstop/ypstart).");
344 if (remove(LOCKFILE) != 0) {
345 syslog(LOG_ERR,
346 "remove(%s) => errno=%d: Please delete file.",
347 LOCKFILE, errno);
349 return (0);
351 rc = mutex_lock(&(shmlockarray->locknode[hashval]));
354 /* Success */
355 return (1);
360 * FUNCTION : unlock_map()
362 * DESCRIPTION: Front end to the unlock routine taking map name as argument.
364 * GIVEN : Map name.
366 * RETURNS : Same as unlock_core
369 unlock_map(char *mapname)
371 int hashval;
373 hashval = hash(mapname);
375 return (unlock_core(hashval));
379 * FUNCTION : unlock_core()
381 * DESCRIPTION: The core map locking function
383 * GIVEN : Map hash value
385 * RETURNS : 0 = Failure
386 * 1 = Success
389 unlock_core(int hashval)
391 int rc;
393 rc = mutex_unlock(&(shmlockarray->locknode[hashval]));
394 if (rc != 0) {
395 syslog(LOG_ERR,
396 "mutex_unlock(): error=%d", rc);
397 syslog(LOG_ERR,
398 "Please restart NIS (ypstop/ypstart).");
399 if (remove(LOCKFILE) != 0) {
400 syslog(LOG_ERR,
401 "remove(%s) => errno=%d: Please delete file.",
402 LOCKFILE, errno);
404 return (0);
407 /* Success */
408 return (1);