1 /* Copyright (c) 1998-2003, 2004 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@suse.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 Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the 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 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 /* nscd - Name Service Cache Daemon. Caches passwd, group, and hosts. */
40 #include <sys/socket.h>
47 #include "../nss/nsswitch.h"
48 #include <device-nrs.h>
50 /* Get libc version number. */
53 #define PACKAGE _libc_intl_domainname
55 /* Structure used by main() thread to keep track of the number of
56 active threads. Used to limit how many threads it will create
57 and under a shutdown condition to wait till all in-progress
58 requests have finished before "turning off the lights". */
63 pthread_cond_t thread_exit_cv
;
64 pthread_mutex_t mutex
;
67 thread_info_t thread_info
;
72 int go_background
= 1;
75 static const char *conffile
= _PATH_NSCDCONF
;
79 uintptr_t pagesize_m1
;
81 static int check_pid (const char *file
);
82 static int write_pid (const char *file
);
84 /* Name and version of program. */
85 static void print_version (FILE *stream
, struct argp_state
*state
);
86 void (*argp_program_version_hook
) (FILE *, struct argp_state
*) = print_version
;
88 /* Definitions of arguments for argp functions. */
89 static const struct argp_option options
[] =
91 { "config-file", 'f', N_("NAME"), 0,
92 N_("Read configuration data from NAME") },
93 { "debug", 'd', NULL
, 0,
94 N_("Do not fork and display messages on the current tty") },
95 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
96 { "shutdown", 'K', NULL
, 0, N_("Shut the server down") },
97 { "statistic", 'g', NULL
, 0, N_("Print current configuration statistic") },
98 { "invalidate", 'i', N_("TABLE"), 0,
99 N_("Invalidate the specified cache") },
100 { "secure", 'S', N_("TABLE,yes"), 0, N_("Use separate cache for each user")},
101 { NULL
, 0, NULL
, 0, NULL
}
104 /* Short description of program. */
105 static const char doc
[] = N_("Name Service Cache Daemon.");
107 /* Prototype for option handler. */
108 static error_t
parse_opt (int key
, char *arg
, struct argp_state
*state
);
110 /* Data structure to communicate with argp functions. */
111 static struct argp argp
=
113 options
, parse_opt
, NULL
, doc
,
116 /* True if only statistics are requested. */
117 static bool get_stats
;
120 main (int argc
, char **argv
)
124 /* Set locale via LC_ALL. */
125 setlocale (LC_ALL
, "");
126 /* Set the text message domain. */
127 textdomain (PACKAGE
);
129 /* Parse and process arguments. */
130 argp_parse (&argp
, argc
, argv
, 0, &remaining
, NULL
);
132 if (remaining
!= argc
)
134 error (0, 0, gettext ("wrong number of arguments"));
135 argp_help (&argp
, stdout
, ARGP_HELP_SEE
, program_invocation_short_name
);
139 /* Read the configuration file. */
140 if (nscd_parse_file (conffile
, dbs
) != 0)
142 /* We couldn't read the configuration file. We don't start the
144 dbg_log (_("cannot read configuration file; this is fatal"));
148 /* Do we only get statistics? */
150 /* Does not return. */
151 receive_print_stats ();
153 /* Check if we are already running. */
154 if (check_pid (_PATH_NSCDPID
))
155 error (EXIT_FAILURE
, 0, _("already running"));
157 /* Remember when we started. */
158 start_time
= time (NULL
);
160 /* Determine page size. */
161 pagesize_m1
= getpagesize () - 1;
163 /* Behave like a daemon. */
170 error (EXIT_FAILURE
, errno
, _("cannot fork"));
174 int nullfd
= open (_PATH_DEVNULL
, O_RDWR
);
179 if (fstat64 (nullfd
, &st
) == 0 && S_ISCHR (st
.st_mode
) != 0
180 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
181 && st
.st_rdev
== makedev (DEV_NULL_MAJOR
, DEV_NULL_MINOR
)
185 /* It is the /dev/null special device alright. */
186 (void) dup2 (nullfd
, STDIN_FILENO
);
187 (void) dup2 (nullfd
, STDOUT_FILENO
);
188 (void) dup2 (nullfd
, STDERR_FILENO
);
195 /* Ugh, somebody is trying to play a trick on us. */
200 int min_close_fd
= nullfd
== -1 ? 0 : STDERR_FILENO
+ 1;
202 DIR *d
= opendir ("/proc/self/fd");
205 struct dirent64
*dirent
;
206 int dfdn
= dirfd (d
);
208 while ((dirent
= readdir64 (d
)) != NULL
)
211 long int fdn
= strtol (dirent
->d_name
, &endp
, 10);
213 if (*endp
== '\0' && fdn
!= dfdn
&& fdn
>= min_close_fd
)
220 for (i
= min_close_fd
; i
< getdtablesize (); i
++)
225 error (EXIT_FAILURE
, errno
, _("cannot fork"));
233 openlog ("nscd", LOG_CONS
| LOG_ODELAY
, LOG_DAEMON
);
235 if (write_pid (_PATH_NSCDPID
) < 0)
236 dbg_log ("%s: %s", _PATH_NSCDPID
, strerror (errno
));
238 if (!init_logfile ())
239 dbg_log (_("Could not create log file"));
241 /* Ignore job control signals. */
242 signal (SIGTTOU
, SIG_IGN
);
243 signal (SIGTTIN
, SIG_IGN
);
244 signal (SIGTSTP
, SIG_IGN
);
247 signal (SIGINT
, termination_handler
);
248 signal (SIGQUIT
, termination_handler
);
249 signal (SIGTERM
, termination_handler
);
250 signal (SIGPIPE
, SIG_IGN
);
252 /* Cleanup files created by a previous 'bind'. */
253 unlink (_PATH_NSCDSOCKET
);
255 /* Make sure we do not get recursive calls. */
256 __nss_disable_nscd ();
258 /* Init databases. */
261 /* Handle incoming requests */
268 /* Handle program arguments. */
270 parse_opt (int key
, char *arg
, struct argp_state
*state
)
285 error (EXIT_FAILURE
, 0, _("Only root is allowed to use this option!"));
287 int sock
= nscd_open_socket ();
294 req
.version
= NSCD_VERSION
;
297 nbytes
= TEMP_FAILURE_RETRY (write (sock
, &req
,
298 sizeof (request_header
)));
300 exit (nbytes
!= sizeof (request_header
) ? EXIT_FAILURE
: EXIT_SUCCESS
);
309 error (EXIT_FAILURE
, 0, _("Only root is allowed to use this option!"));
312 int sock
= nscd_open_socket ();
321 if (strcmp (arg
, "passwd") == 0)
322 req
.key_len
= sizeof "passwd";
323 else if (strcmp (arg
, "group") == 0)
324 req
.key_len
= sizeof "group";
325 else if (strcmp (arg
, "hosts") == 0)
326 req
.key_len
= sizeof "hosts";
328 return ARGP_ERR_UNKNOWN
;
330 req
.version
= NSCD_VERSION
;
331 req
.type
= INVALIDATE
;
333 iov
[0].iov_base
= &req
;
334 iov
[0].iov_len
= sizeof (req
);
335 iov
[1].iov_base
= (void *) key
;
336 iov
[1].iov_len
= req
.key_len
;
338 nbytes
= TEMP_FAILURE_RETRY (writev (sock
, iov
, 2));
342 exit (nbytes
!= iov
[0].iov_len
+ iov
[1].iov_len
343 ? EXIT_FAILURE
: EXIT_SUCCESS
);
347 nthreads
= atol (arg
);
351 if (strcmp (arg
, "passwd,yes") == 0)
352 secure_in_use
= dbs
[pwddb
].secure
= 1;
353 else if (strcmp (arg
, "group,yes") == 0)
354 secure_in_use
= dbs
[grpdb
].secure
= 1;
355 else if (strcmp (arg
, "hosts,yes") == 0)
356 secure_in_use
= dbs
[hstdb
].secure
= 1;
360 return ARGP_ERR_UNKNOWN
;
366 /* Print the version information. */
368 print_version (FILE *stream
, struct argp_state
*state
)
370 fprintf (stream
, "nscd (GNU %s) %s\n", PACKAGE
, VERSION
);
371 fprintf (stream
, gettext ("\
372 Copyright (C) %s Free Software Foundation, Inc.\n\
373 This is free software; see the source for copying conditions. There is NO\n\
374 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
376 fprintf (stream
, gettext ("Written by %s.\n"),
377 "Thorsten Kukuk and Ulrich Drepper");
381 /* Create a socket connected to a name. */
383 nscd_open_socket (void)
385 struct sockaddr_un addr
;
388 sock
= socket (PF_UNIX
, SOCK_STREAM
, 0);
392 addr
.sun_family
= AF_UNIX
;
393 assert (sizeof (addr
.sun_path
) >= sizeof (_PATH_NSCDSOCKET
));
394 strcpy (addr
.sun_path
, _PATH_NSCDSOCKET
);
395 if (connect (sock
, (struct sockaddr
*) &addr
, sizeof (addr
)) < 0)
406 termination_handler (int signum
)
410 /* Clean up the file created by 'bind'. */
411 unlink (_PATH_NSCDSOCKET
);
413 /* Clean up pid file. */
414 unlink (_PATH_NSCDPID
);
416 // XXX Terminate threads.
418 /* Synchronize memory. */
419 for (int cnt
= 0; cnt
< lastdb
; ++cnt
)
420 if (dbs
[cnt
].persistent
)
422 msync (dbs
[cnt
].head
, dbs
[cnt
].memsize
, MS_ASYNC
);
424 _exit (EXIT_SUCCESS
);
427 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
429 check_pid (const char *file
)
433 fp
= fopen (file
, "r");
439 n
= fscanf (fp
, "%d", &pid
);
442 if (n
!= 1 || kill (pid
, 0) == 0)
449 /* Write the current process id to the file FILE.
450 Returns 0 if successful, -1 if not. */
452 write_pid (const char *file
)
456 fp
= fopen (file
, "w");
460 fprintf (fp
, "%d\n", getpid ());
461 if (fflush (fp
) || ferror (fp
))