4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2015 Gary Mills
24 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
29 * DESCRIPTION: Contains the map update thread and related code.
42 #include "../ldap_util.h"
44 /* Enable standard YP code features defined in ypdefs.h */
57 suc_code
update_from_dit(map_ctrl
*, datum
*);
58 void * update_thread(void *);
63 extern pid_t parent_pid
;
66 * FUNCTION: update_entry_if_required()
68 * DESCRIPTION: Determines if an entry is to be updated and if it is does the
71 * GIVEN : Pointer to the open map ctrl
72 * Pointer to the entry key
74 * RETURNS : SUCCESS = Entry is in a state to be returned to the client
75 * i.e. either got updated, did not need to be updated or we are
76 * in a mode where it is acceptable to return out of date
78 * FAILURE = Entry need an update but it could not be done.
81 update_entry_if_required(map_ctrl
*map
, datum
*key
)
84 /* Only update individual entries if entire map is */
85 /* not being updated */
86 if (is_map_updating(map
))
90 * If we are being asked for the order then need to check if
91 * the map is in need of an update. If it is then fake a
92 * recent order. The client will then read the map, using
93 * dbm_firstkey and this will do the update.
95 if (0 == strncmp(key
->dptr
, yp_last_modified
, yp_last_modified_sz
)) {
96 if (has_map_expired(map
))
97 update_timestamp(map
->entries
);
101 /* Never update special keys. Have no TTLs */
102 if (is_special_key(key
))
105 if (!has_entry_expired(map
, key
))
106 /* Didn't need an update */
110 return (update_from_dit(map
, key
));
114 * FUNCTION: update_from_dit()
116 * DESCRIPTION: Called to update an entry from the DIT
118 * INPUTS: Map control structure for an open map
121 * OUTPUTS: SUCCESS = Update complete or we are in a mode where it is
122 * acceptable to return out of date information.
123 * FAILURE = Update failed
127 update_from_dit(map_ctrl
*map
, datum
*key
)
134 * Netgroup maps are a special case we cannot update just one entry so
135 * update the entire map instead.
137 if ((0 == strcmp(map
->map_name
, NETGROUP_BYHOST
)) ||
138 (0 == strcmp(map
->map_name
, NETGROUP_BYUSER
))) {
139 return (update_map_if_required(map
, FALSE
));
142 /* Read entry from the DIT */
143 ret
= read_from_dit(map
->map_name
, map
->domain
, key
, &dat
);
145 /* Check that we got something */
146 if (NULL
== dat
.dptr
) {
149 * In a mode where it is acceptable to return out of
152 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
153 "LDAP inaccessible returning old information");
157 * In a mode where it is not acceptable to return out
158 * of date information.
160 * If the error positviely indicates that there is no
161 * such entry delete it. For errors where object may
162 * still exist in the DIT leave it.
164 if (MAP_NO_MATCHING_KEY
== ret
) {
166 * Don't log errors. If the entry was not
167 * already present then no problem. The user
168 * just asked us for a non existant entry.
170 dbm_delete(map
->entries
, *key
);
171 dbm_delete(map
->ttl
, *key
);
177 /* Write it to DBM */
178 res
= dbm_store(map
->entries
, *key
, dat
, DBM_REPLACE
);
185 update_entry_ttl(map
, key
, TTL_RUNNING
);
191 * FUNCTION: update_map_if_required()
193 * DESCRIPTION: Called to update an entire map if it is out of date. Map ctrl
194 * must be locked before this is called. This handles checking if
195 * the map is already being updated. It is important that this is
196 * done atomically with obtaining the maps update lock.
198 * INPUTS: Map control structure for an open map
199 * Flag indication if we should wait for completion
201 * OUTPUTS: SUCCESS = Map update initiated
202 * FAILURE = Map update not initiated
205 update_map_if_required(map_ctrl
*map
, bool_t wait
)
214 * Actually get the lock
216 * May block so unlock map_ctrl while it is done
218 unlock_map_ctrl(map
);
219 res
= lock_map_update(map
);
221 if (SUCCESS
!= res
) {
222 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
223 "Could not lock map %s for update",
228 /* If not waiting try to get the lock */
229 switch (try_lock_map_update(map
)) {
232 * We got the lock. Continue to start an update.
238 * Some one else got the lock. OK they are
239 * doing the update so we can just return.
245 * Some serious problem with lock.
252 * If we get here are holding the update lock. Make a final check that
253 * nobody beat us to the map update while we were getting it.
255 if (!has_map_expired(map
)) {
256 /* A big waste of time. Somebody else did the update */
257 unlock_map_update(map
);
262 * We got the lock and nobody beat us to doing the update. Start our
265 * Thread will free the update lock when update is complete.
270 * Make a copy of the map_ctrl structure so the update thread has an
271 * independent version to work with. Note: Must not be on stack.
273 * On exit the update thread must free this.
275 new_map
= dup_map_ctrl(map
);
276 if (NULL
== new_map
) {
277 unlock_map_update(map
);
282 * While thread is running unlock map so other processes can
283 * execute non update related accesses
285 unlock_map_ctrl(map
);
287 flags
= THR_BOUND
| THR_NEW_LWP
;
290 * If we are not going to thr_join then need to create detached.
291 * This prevents a zombie being left when nobody joins us.
293 if (!wait
&& (getpid() == parent_pid
))
294 flags
|= THR_DETACHED
;
296 /* Kick off update thread */
297 if (0 != thr_create(NULL
, 0, update_thread
, new_map
,
299 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
300 "Could not create NIS update thread");
301 free_map_ctrl(new_map
);
302 unlock_map_update(map
);
303 if (SUCCESS
!= lock_map_ctrl(map
))
304 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
305 "Could not acquire update lock for %s", map
->map_name
);
310 /* May block but no problem map_ctrl is already unlocked. */
311 thr_join(tid
, NULL
, NULL
);
314 /* Re acquire lock */
315 if (1 != lock_map_ctrl(map
)) {
316 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
317 "Could not re-acquire lock for %s", map
->map_name
);
325 * FUNCTION: update_thread()
327 * DESCRIPTION: The update thread this is called to update an entire NIS map.
328 * if several NIS maps are found to be out of date several
329 * instances of this may be running at the same time.
331 * Since we are using a duplicate map_ctrl we do not have to lock
332 * it. If we did would end up using the same mutex as the parent
333 * map ctrl an possibly deadlocking.
335 * INPUTS: Map handle (because we need access to name and lock)
337 * OUTPUTS: None exits when finished.
341 update_thread(void *arg
)
343 void *ret
= (void *)-1;
346 /* Cast argument pointer to correct type */
347 map
= (map_ctrl
*)arg
;
349 /* Actually do the work */
350 if (SUCCESS
== update_map_from_dit(map
, FALSE
))
353 /* Update complete or failed */
354 unlock_map_update(map
);
356 /* Free up duplicate copy of the map_ctrl */
365 * FUNCTION : is_special_key()
367 * DESCRIPTION: Works out if a given key is one of the special ones. We just
368 * check for the "YP_" prefix. This is not 100% safe but if
369 * valid keys with a "YP_" prefix exist in the DIT then a lot of
370 * other parts of NIS wont work.
373 is_special_key(datum
*key
)
375 if (0 == strncmp(key
->dptr
, yp_prefix
, yp_prefix_sz
))