1 /* Copyright (C) 1997 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
26 #include <rpcsvc/nis.h>
27 #include <rpcsvc/nis_cache.h>
28 #include <bits/libc-lock.h>
30 #include "nis_intern.h"
32 static struct timeval TIMEOUT
= {10, 0};
34 #define HEADER_MAGIC 0x07021971
35 #define SPACER_MAGIC 0x07654321
37 #define CACHE_VERSION 0x00000001
41 u_long magic
; /* Magic number */
42 u_long vers
; /* Cache file format version */
43 u_short tcp_port
; /* tcp port of nis_cachemgr */
44 u_short udp_port
; /* udp port of nis_cachemgr */
45 u_long entries
; /* Number of cached objs. */
46 off_t used
; /* How many space are used ? */
48 typedef struct cache_header cache_header
;
52 u_long magic
; /* Magic number */
54 time_t ctime
; /* time we have created this object */
55 time_t ttl
; /* time to life of this object */
58 typedef struct cache_spacer cache_spacer
;
60 static int cache_fd
= -1;
62 static caddr_t maddr
= NULL
;
64 static CLIENT
*cache_clnt
= NULL
;
66 /* If there is no cachemgr, we shouldn't use NIS_SHARED_DIRCACHE, if
67 there is no NIS_SHARED_DIRCACHE, we couldn't use nis_cachemgr.
68 So, if the clnt_call to nis_cachemgr fails, we also close the cache file.
69 But another thread could read the cache => lock the cache_fd and cache_clnt
70 variables with the same lock */
71 __libc_lock_define_initialized (static, mgrlock
)
73 /* close file handles and nis_cachemgr connection */
82 if (cache_clnt
!= NULL
)
84 clnt_destroy (cache_clnt
);
90 /* open the cache file and connect to nis_cachemgr */
94 struct sockaddr_in sin
;
97 if ((cache_fd
= open (CACHEFILE
, O_RDONLY
)) == -1)
100 if (read (cache_fd
, &hptr
, sizeof (cache_header
)) == -1
101 || lseek (cache_fd
, 0, SEEK_SET
) < 0)
107 if (hptr
.magic
!= HEADER_MAGIC
)
111 syslog (LOG_ERR
, _("NIS+: cache file is corrupt!"));
115 memset (&sin
, '\0', sizeof (sin
));
116 sin
.sin_family
= AF_INET
;
117 clnt_sock
= RPC_ANYSOCK
;
118 sin
.sin_addr
.s_addr
= htonl (INADDR_LOOPBACK
);
119 sin
.sin_port
= htons (hptr
.tcp_port
);
120 cache_clnt
= clnttcp_create (&sin
, CACHEPROG
, CACHE_VER_1
, &clnt_sock
, 0, 0);
121 if (cache_clnt
== NULL
)
127 /* If the program exists, close the socket */
128 if (fcntl (clnt_sock
, F_SETFD
, FD_CLOEXEC
) == -1)
129 perror (_("fcntl: F_SETFD"));
133 /* Ask the cache manager to update directory 'name'
134 for us (because the ttl has expired). */
136 __cache_refresh (nis_name name
)
139 nis_error result
= NIS_SUCCESS
;
141 __libc_lock_lock (mgrlock
);
143 if (cache_clnt
== NULL
)
145 else if (clnt_call (cache_clnt
, NIS_CACHE_REFRESH_ENTRY
,
146 (xdrproc_t
) xdr_wrapstring
, (caddr_t
) &name
,
147 (xdrproc_t
) xdr_void
, &clnt_res
, TIMEOUT
)
154 __libc_lock_unlock (mgrlock
);
160 __cache_find (const_nis_name name
, directory_obj
**obj
)
163 struct cache_header
*hptr
;
164 struct cache_spacer
*cs
;
165 struct directory_obj
*dir
;
168 time_t now
= time (NULL
);
173 hash
= __nis_hash (name
, strlen(name
));
174 hptr
= (cache_header
*)maddr
;
175 if ((hptr
->magic
!= HEADER_MAGIC
) || (hptr
->vers
!= CACHE_VERSION
))
177 syslog (LOG_ERR
, _("NIS+: cache file is corrupt!"));
178 return NIS_SYSTEMERROR
;
180 cs
= (cache_spacer
*)(maddr
+ sizeof (cache_header
));
181 while (cs
->next_offset
)
183 if (cs
->magic
!= SPACER_MAGIC
)
185 syslog (LOG_ERR
, _("NIS+: cache file is corrupt!"));
186 return NIS_SYSTEMERROR
;
188 if (cs
->hashval
== hash
)
190 if ((now
- cs
->ctime
) > cs
->ttl
)
191 return NIS_CACHEEXPIRED
;
192 dir
= calloc (1, sizeof (directory_obj
));
193 addr
= (caddr_t
)cs
+ sizeof (cache_spacer
);
194 xdrmem_create (&xdrs
, addr
, cs
->next_offset
, XDR_DECODE
);
195 xdr_directory_obj (&xdrs
, dir
);
201 ptr
+= cs
->next_offset
+ sizeof (struct cache_spacer
);
202 cs
= (struct cache_spacer
*)ptr
;
207 static directory_obj
*
208 internal_cache_search (const_nis_name name
)
212 int second_refresh
= 0;
216 if (__cache_open () == FALSE
)
220 /* This lock is for nis_cachemgr, so it couldn't write a new cache
221 file if we reading it */
222 if (__nis_lock_cache () == -1)
226 munmap (maddr
, msize
);
227 if (fstat (cache_fd
, &s
) < 0)
232 maddr
= mmap (0, msize
, PROT_READ
, MAP_SHARED
, cache_fd
, 0);
234 if (maddr
== MAP_FAILED
)
236 __nis_unlock_cache ();
240 res
= __cache_find (name
, &dir
);
242 munmap (maddr
, msize
);
244 /* Allow nis_cachemgr to write a new cachefile */
245 __nis_unlock_cache ();
249 case NIS_CACHEEXPIRED
:
254 _("NIS+: nis_cachemgr failed to refresh object for us"));
258 if (__cache_refresh ((char *) name
) != NIS_SUCCESS
)
270 __cache_search (const_nis_name name
)
274 __libc_lock_lock (mgrlock
);
276 dir
= internal_cache_search (name
);
278 __libc_lock_unlock (mgrlock
);
284 __cache_add (fd_result
*fd
)
287 nis_error result
= NIS_SUCCESS
;
289 __libc_lock_lock (mgrlock
);
291 if (cache_clnt
== NULL
)
292 if (__cache_open () == FALSE
)
295 if (cache_clnt
!= NULL
&&
296 (clnt_call (cache_clnt
, NIS_CACHE_ADD_ENTRY
, (xdrproc_t
) xdr_fd_result
,
297 (caddr_t
)fd
, (xdrproc_t
) xdr_void
, &clnt_res
, TIMEOUT
)
301 result
= NIS_RPCERROR
;
304 __libc_lock_unlock (mgrlock
);