1 /* Copyright (c) 1998 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
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 <sys/types.h>
32 static unsigned long modulo
= 211;
33 static unsigned long postimeout
= 3600;
34 static unsigned long negtimeout
= 60;
36 static unsigned long poshit
= 0;
37 static unsigned long posmiss
= 0;
38 static unsigned long neghit
= 0;
39 static unsigned long negmiss
= 0;
47 typedef struct grphash grphash
;
54 typedef struct gidhash gidhash
;
62 typedef struct neghash neghash
;
64 static grphash
*grptbl
;
65 static gidhash
*gidtbl
;
66 static neghash
*negtbl
;
68 static pthread_rwlock_t grplock
= PTHREAD_RWLOCK_INITIALIZER
;
69 static pthread_rwlock_t neglock
= PTHREAD_RWLOCK_INITIALIZER
;
71 static void *grptable_update (void *);
72 static void *negtable_update (void *);
75 get_gr_stat (stat_response_header
*stat
)
77 stat
->gr_poshit
= poshit
;
78 stat
->gr_posmiss
= posmiss
;
79 stat
->gr_neghit
= neghit
;
80 stat
->gr_negmiss
= negmiss
;
81 stat
->gr_size
= modulo
;
82 stat
->gr_posttl
= postimeout
;
83 stat
->gr_negttl
= negtimeout
;
87 set_grp_modulo (unsigned long mod
)
93 set_pos_grp_ttl (unsigned long ttl
)
99 set_neg_grp_ttl (unsigned long ttl
)
110 grptbl
= calloc (modulo
, sizeof (grphash
));
113 gidtbl
= calloc (modulo
, sizeof (grphash
));
116 negtbl
= calloc (modulo
, sizeof (neghash
));
120 pthread_attr_init (&attr
);
121 pthread_attr_setdetachstate (&attr
, PTHREAD_CREATE_DETACHED
);
123 pthread_create (&thread
, NULL
, grptable_update
, &attr
);
124 pthread_create (&thread
, NULL
, negtable_update
, &attr
);
126 pthread_attr_destroy (&attr
);
131 static struct group
*
132 save_grp (struct group
*src
)
137 dest
= calloc (1, sizeof (struct group
));
138 dest
->gr_name
= strdup (src
->gr_name
);
139 dest
->gr_passwd
= strdup (src
->gr_passwd
);
140 dest
->gr_gid
= src
->gr_gid
;
142 /* How many members does this group have? */
144 while (src
->gr_mem
[l
])
147 dest
->gr_mem
= calloc (1, sizeof (char *) * (l
+1));
149 while (src
->gr_mem
[l
])
151 dest
->gr_mem
[l
] = strdup (src
->gr_mem
[l
]);
159 free_grp (struct group
*src
)
164 free (src
->gr_passwd
);
167 while (src
->gr_mem
[l
])
169 free (src
->gr_mem
[l
]);
177 add_cache (struct group
*grp
)
181 unsigned long int hash
= __nis_hash (grp
->gr_name
,
182 strlen (grp
->gr_name
)) % modulo
;
185 dbg_log (_("grp_add_cache (%s)"), grp
->gr_name
);
187 work
= &grptbl
[hash
];
189 if (grptbl
[hash
].grp
== NULL
)
190 grptbl
[hash
].grp
= save_grp (grp
);
193 while (work
->next
!= NULL
)
196 work
->next
= calloc (1, sizeof (grphash
));
197 work
->next
->grp
= save_grp (grp
);
201 time (&work
->create
);
202 gidwork
= &gidtbl
[grp
->gr_gid
% modulo
];
203 if (gidwork
->grptr
== NULL
)
204 gidwork
->grptr
= work
->grp
;
207 while (gidwork
->next
!= NULL
)
208 gidwork
= gidwork
->next
;
210 gidwork
->next
= calloc (1, sizeof (gidhash
));
211 gidwork
->next
->grptr
= work
->grp
;
217 static struct group
*
218 cache_search_name (const char *name
)
221 unsigned long int hash
= __nis_hash (name
, strlen(name
)) % modulo
;
223 work
= &grptbl
[hash
];
225 while (work
->grp
!= NULL
)
227 if (strcmp (work
->grp
->gr_name
, name
) == 0)
229 if (work
->next
!= NULL
)
237 static struct group
*
238 cache_search_gid (gid_t gid
)
242 work
= &gidtbl
[gid
% modulo
];
244 while (work
->grptr
!= NULL
)
246 if (work
->grptr
->gr_gid
== gid
)
248 if (work
->next
!= NULL
)
257 add_negcache (char *key
)
260 unsigned long int hash
= __nis_hash (key
, strlen (key
)) % modulo
;
263 dbg_log (_("grp_add_netgache (%s|%ld)"), key
, hash
);
265 work
= &negtbl
[hash
];
267 if (negtbl
[hash
].key
== NULL
)
269 negtbl
[hash
].key
= strdup (key
);
270 negtbl
[hash
].next
= NULL
;
274 while (work
->next
!= NULL
)
277 work
->next
= calloc (1, sizeof (neghash
));
278 work
->next
->key
= strdup (key
);
282 time (&work
->create
);
287 cache_search_neg (const char *key
)
290 unsigned long int hash
= __nis_hash (key
, strlen (key
)) % modulo
;
293 dbg_log (_("grp_cache_search_neg (%s|%ld)"), key
, hash
);
295 work
= &negtbl
[hash
];
297 while (work
->key
!= NULL
)
299 if (strcmp (work
->key
, key
) == 0)
301 if (work
->next
!= NULL
)
310 cache_getgrnam (void *v_param
)
312 param_t
*param
= (param_t
*)v_param
;
315 pthread_rwlock_rdlock (&grplock
);
316 grp
= cache_search_name (param
->key
);
318 /* I don't like it to hold the read only lock longer, but it is
319 necessary to avoid to much malloc/free/strcpy. */
324 dbg_log (_("Found \"%s\" in cache !"), param
->key
);
327 gr_send_answer (param
->conn
, grp
);
328 close_socket (param
->conn
);
330 pthread_rwlock_unlock (&grplock
);
336 char *buffer
= calloc (1, buflen
);
337 struct group resultbuf
;
340 dbg_log (_("Doesn't found \"%s\" in cache !"), param
->key
);
342 pthread_rwlock_unlock (&grplock
);
344 pthread_rwlock_rdlock (&neglock
);
345 status
= cache_search_neg (param
->key
);
346 pthread_rwlock_unlock (&neglock
);
350 while (buffer
!= NULL
351 && (getgrnam_r (param
->key
, &resultbuf
, buffer
, buflen
, &grp
)
357 buffer
= realloc (buffer
, buflen
);
360 if (buffer
!= NULL
&& grp
!= NULL
)
365 pthread_rwlock_wrlock (&grplock
);
366 /* While we are waiting on the lock, somebody else could
368 tmp
= cache_search_name (param
->key
);
371 pthread_rwlock_unlock (&grplock
);
375 pthread_rwlock_wrlock (&neglock
);
376 add_negcache (param
->key
);
378 pthread_rwlock_unlock (&neglock
);
384 gr_send_answer (param
->conn
, grp
);
385 close_socket (param
->conn
);
395 cache_gr_disabled (void *v_param
)
397 param_t
*param
= (param_t
*)v_param
;
400 dbg_log (_("\tgroup cache is disabled\n"));
402 gr_send_disabled (param
->conn
);
407 cache_getgrgid (void *v_param
)
409 param_t
*param
= (param_t
*)v_param
;
410 struct group
*grp
, resultbuf
;
411 gid_t gid
= strtol (param
->key
, NULL
, 10);
413 pthread_rwlock_rdlock (&grplock
);
414 grp
= cache_search_gid (gid
);
416 /* I don't like it to hold the read only lock longer, but it is
417 necessary to avoid to much malloc/free/strcpy. */
422 dbg_log (_("Found \"%d\" in cache !"), gid
);
425 gr_send_answer (param
->conn
, grp
);
426 close_socket (param
->conn
);
428 pthread_rwlock_unlock (&grplock
);
433 char *buffer
= malloc (buflen
);
437 dbg_log (_("Doesn't found \"%d\" in cache !"), gid
);
439 pthread_rwlock_unlock (&grplock
);
441 pthread_rwlock_rdlock (&neglock
);
442 status
= cache_search_neg (param
->key
);
443 pthread_rwlock_unlock (&neglock
);
447 while (buffer
!= NULL
448 && (getgrgid_r (gid
, &resultbuf
, buffer
, buflen
, &grp
) != 0)
453 buffer
= realloc (buffer
, buflen
);
456 if (buffer
!= NULL
&& grp
!= NULL
)
461 pthread_rwlock_wrlock (&grplock
);
462 /* While we are waiting on the lock, somebody else could
464 tmp
= cache_search_gid (gid
);
467 pthread_rwlock_unlock (&grplock
);
472 pthread_rwlock_wrlock (&neglock
);
473 add_negcache (param
->key
);
474 pthread_rwlock_unlock (&neglock
);
480 gr_send_answer (param
->conn
, grp
);
481 close_socket (param
->conn
);
491 grptable_update (void *v
)
501 dbg_log (_("(grptable_update) Wait for write lock!"));
503 pthread_rwlock_wrlock (&grplock
);
506 dbg_log (_("(grptable_update) Have write lock"));
509 for (i
= 0; i
< modulo
; ++i
)
511 grphash
*work
= &grptbl
[i
];
513 while (work
&& work
->grp
)
515 if ((now
- work
->create
) >= postimeout
)
517 gidhash
*uh
= &gidtbl
[work
->grp
->gr_gid
% modulo
];
520 dbg_log (_("Give \"%s\" free"), work
->grp
->gr_name
);
522 while (uh
&& uh
->grptr
)
524 if (uh
->grptr
->gr_gid
== work
->grp
->gr_gid
)
527 dbg_log (_("Give gid for \"%s\" free"),
529 if (uh
->next
!= NULL
)
531 gidhash
*tmp
= uh
->next
;
532 uh
->grptr
= tmp
->grptr
;
533 uh
->next
= tmp
->next
;
542 free_grp (work
->grp
);
543 if (work
->next
!= NULL
)
545 grphash
*tmp
= work
->next
;
546 work
->create
= tmp
->create
;
547 work
->next
= tmp
->next
;
548 work
->grp
= tmp
->grp
;
558 dbg_log (_("(grptable_update) Release wait lock"));
559 pthread_rwlock_unlock (&grplock
);
566 negtable_update (void *v
)
576 dbg_log (_("(neggrptable_update) Wait for write lock!"));
578 pthread_rwlock_wrlock (&neglock
);
581 dbg_log (_("(neggrptable_update) Have write lock"));
584 for (i
= 0; i
< modulo
; ++i
)
586 neghash
*work
= &negtbl
[i
];
588 while (work
&& work
->key
)
590 if ((now
- work
->create
) >= negtimeout
)
593 dbg_log (_("Give \"%s\" free"), work
->key
);
597 if (work
->next
!= NULL
)
599 neghash
*tmp
= work
->next
;
600 work
->create
= tmp
->create
;
601 work
->next
= tmp
->next
;
602 work
->key
= tmp
->key
;
612 dbg_log (_("(neggrptable_update) Release wait lock"));
613 pthread_rwlock_unlock (&neglock
);