1 /* Copyright (c) 1998-2006, 2007 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; version 2 of the License, or
8 (at your option) any later version.
10 This program 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
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19 /* nscd - Name Service Cache Daemon. Caches passwd, group, and hosts. */
39 #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;
74 static const char *conffile
= _PATH_NSCDCONF
;
78 uintptr_t pagesize_m1
;
82 time_t restart_interval
= RESTART_INTERVAL
;
87 static int check_pid (const char *file
);
88 static int write_pid (const char *file
);
90 /* Name and version of program. */
91 static void print_version (FILE *stream
, struct argp_state
*state
);
92 void (*argp_program_version_hook
) (FILE *, struct argp_state
*) = print_version
;
94 /* Definitions of arguments for argp functions. */
95 static const struct argp_option options
[] =
97 { "config-file", 'f', N_("NAME"), 0,
98 N_("Read configuration data from NAME") },
99 { "debug", 'd', NULL
, 0,
100 N_("Do not fork and display messages on the current tty") },
101 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
102 { "shutdown", 'K', NULL
, 0, N_("Shut the server down") },
103 { "statistic", 'g', NULL
, 0, N_("Print current configuration statistic") },
104 { "invalidate", 'i', N_("TABLE"), 0,
105 N_("Invalidate the specified cache") },
106 { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN
,
107 N_("Use separate cache for each user")},
108 { NULL
, 0, NULL
, 0, NULL
}
111 /* Short description of program. */
112 static const char doc
[] = N_("Name Service Cache Daemon.");
114 /* Prototype for option handler. */
115 static error_t
parse_opt (int key
, char *arg
, struct argp_state
*state
);
117 /* Data structure to communicate with argp functions. */
118 static struct argp argp
=
120 options
, parse_opt
, NULL
, doc
,
123 /* The SIGHUP handler is extern to this file */
124 extern void sighup_handler(int signum
);
126 /* True if only statistics are requested. */
127 static bool get_stats
;
130 main (int argc
, char **argv
)
134 /* Set locale via LC_ALL. */
135 setlocale (LC_ALL
, "");
136 /* Set the text message domain. */
137 textdomain (PACKAGE
);
139 /* Determine if the kernel has SELinux support. */
140 nscd_selinux_enabled (&selinux_enabled
);
142 /* Parse and process arguments. */
143 argp_parse (&argp
, argc
, argv
, 0, &remaining
, NULL
);
145 if (remaining
!= argc
)
147 error (0, 0, gettext ("wrong number of arguments"));
148 argp_help (&argp
, stdout
, ARGP_HELP_SEE
, program_invocation_short_name
);
152 /* Read the configuration file. */
153 if (nscd_parse_file (conffile
, dbs
) != 0)
154 /* We couldn't read the configuration file. We don't start the
156 error (EXIT_FAILURE
, 0,
157 _("failure while reading configuration file; this is fatal"));
159 /* Do we only get statistics? */
161 /* Does not return. */
162 receive_print_stats ();
164 /* Check if we are already running. */
165 if (check_pid (_PATH_NSCDPID
))
166 error (EXIT_FAILURE
, 0, _("already running"));
168 /* Remember when we started. */
169 start_time
= time (NULL
);
171 /* Determine page size. */
172 pagesize_m1
= getpagesize () - 1;
174 /* Behave like a daemon. */
181 error (EXIT_FAILURE
, errno
, _("cannot fork"));
185 int nullfd
= open (_PATH_DEVNULL
, O_RDWR
);
190 if (fstat64 (nullfd
, &st
) == 0 && S_ISCHR (st
.st_mode
) != 0
191 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
192 && st
.st_rdev
== makedev (DEV_NULL_MAJOR
, DEV_NULL_MINOR
)
196 /* It is the /dev/null special device alright. */
197 (void) dup2 (nullfd
, STDIN_FILENO
);
198 (void) dup2 (nullfd
, STDOUT_FILENO
);
199 (void) dup2 (nullfd
, STDERR_FILENO
);
206 /* Ugh, somebody is trying to play a trick on us. */
211 int min_close_fd
= nullfd
== -1 ? 0 : STDERR_FILENO
+ 1;
213 DIR *d
= opendir ("/proc/self/fd");
216 struct dirent64
*dirent
;
217 int dfdn
= dirfd (d
);
219 while ((dirent
= readdir64 (d
)) != NULL
)
222 long int fdn
= strtol (dirent
->d_name
, &endp
, 10);
224 if (*endp
== '\0' && fdn
!= dfdn
&& fdn
>= min_close_fd
)
231 for (i
= min_close_fd
; i
< getdtablesize (); i
++)
236 error (EXIT_FAILURE
, errno
, _("cannot fork"));
242 if (chdir ("/") != 0)
243 error (EXIT_FAILURE
, errno
,
244 _("cannot change current working directory to \"/\""));
246 openlog ("nscd", LOG_CONS
| LOG_ODELAY
, LOG_DAEMON
);
248 if (write_pid (_PATH_NSCDPID
) < 0)
249 dbg_log ("%s: %s", _PATH_NSCDPID
, strerror (errno
));
251 if (!init_logfile ())
252 dbg_log (_("Could not create log file"));
254 /* Ignore job control signals. */
255 signal (SIGTTOU
, SIG_IGN
);
256 signal (SIGTTIN
, SIG_IGN
);
257 signal (SIGTSTP
, SIG_IGN
);
260 /* In foreground mode we are not paranoid. */
263 /* Start the SELinux AVC. */
267 signal (SIGINT
, termination_handler
);
268 signal (SIGQUIT
, termination_handler
);
269 signal (SIGTERM
, termination_handler
);
270 signal (SIGHUP
, sighup_handler
);
271 signal (SIGPIPE
, SIG_IGN
);
273 /* Cleanup files created by a previous 'bind'. */
274 unlink (_PATH_NSCDSOCKET
);
276 /* Make sure we do not get recursive calls. */
277 __nss_disable_nscd ();
279 /* Init databases. */
282 /* Handle incoming requests */
289 /* Handle program arguments. */
291 parse_opt (int key
, char *arg
, struct argp_state
*state
)
306 error (4, 0, _("Only root is allowed to use this option!"));
308 int sock
= nscd_open_socket ();
314 req
.version
= NSCD_VERSION
;
318 ssize_t nbytes
= TEMP_FAILURE_RETRY (send (sock
, &req
,
319 sizeof (request_header
),
322 exit (nbytes
!= sizeof (request_header
) ? EXIT_FAILURE
: EXIT_SUCCESS
);
331 error (4, 0, _("Only root is allowed to use this option!"));
334 int sock
= nscd_open_socket ();
340 for (cnt
= pwddb
; cnt
< lastdb
; ++cnt
)
341 if (strcmp (arg
, dbnames
[cnt
]) == 0)
345 return ARGP_ERR_UNKNOWN
;
347 size_t arg_len
= strlen (arg
) + 1;
354 reqdata
.req
.key_len
= strlen (arg
) + 1;
355 reqdata
.req
.version
= NSCD_VERSION
;
356 reqdata
.req
.type
= INVALIDATE
;
357 memcpy (reqdata
.arg
, arg
, arg_len
);
359 ssize_t nbytes
= TEMP_FAILURE_RETRY (send (sock
, &reqdata
,
360 sizeof (request_header
)
364 if (nbytes
!= sizeof (request_header
) + arg_len
)
368 error (EXIT_FAILURE
, err
, _("write incomplete"));
371 /* Wait for ack. Older nscd just closed the socket when
372 prune_cache finished, silently ignore that. */
374 nbytes
= TEMP_FAILURE_RETRY (read (sock
, &resp
, sizeof (resp
)));
375 if (nbytes
!= 0 && nbytes
!= sizeof (resp
))
379 error (EXIT_FAILURE
, err
, _("cannot read invalidate ACK"));
385 error (EXIT_FAILURE
, resp
, _("invalidation failed"));
391 nthreads
= atol (arg
);
395 error (0, 0, _("secure services not implemented anymore"));
399 return ARGP_ERR_UNKNOWN
;
405 /* Print the version information. */
407 print_version (FILE *stream
, struct argp_state
*state
)
409 fprintf (stream
, "nscd (GNU %s) %s\n", PACKAGE
, VERSION
);
410 fprintf (stream
, gettext ("\
411 Copyright (C) %s Free Software Foundation, Inc.\n\
412 This is free software; see the source for copying conditions. There is NO\n\
413 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
415 fprintf (stream
, gettext ("Written by %s.\n"),
416 "Thorsten Kukuk and Ulrich Drepper");
420 /* Create a socket connected to a name. */
422 nscd_open_socket (void)
424 struct sockaddr_un addr
;
427 sock
= socket (PF_UNIX
, SOCK_STREAM
, 0);
431 addr
.sun_family
= AF_UNIX
;
432 assert (sizeof (addr
.sun_path
) >= sizeof (_PATH_NSCDSOCKET
));
433 strcpy (addr
.sun_path
, _PATH_NSCDSOCKET
);
434 if (connect (sock
, (struct sockaddr
*) &addr
, sizeof (addr
)) < 0)
446 termination_handler (int signum
)
450 /* Clean up the file created by 'bind'. */
451 unlink (_PATH_NSCDSOCKET
);
453 /* Clean up pid file. */
454 unlink (_PATH_NSCDPID
);
456 // XXX Terminate threads.
458 /* Synchronize memory. */
459 for (int cnt
= 0; cnt
< lastdb
; ++cnt
)
461 if (!dbs
[cnt
].enabled
)
464 /* Make sure nobody keeps using the database. */
465 dbs
[cnt
].head
->timestamp
= 0;
467 if (dbs
[cnt
].persistent
)
469 msync (dbs
[cnt
].head
, dbs
[cnt
].memsize
, MS_ASYNC
);
472 /* Shutdown the SELinux AVC. */
476 _exit (EXIT_SUCCESS
);
479 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
481 check_pid (const char *file
)
485 fp
= fopen (file
, "r");
491 n
= fscanf (fp
, "%d", &pid
);
494 /* If we cannot parse the file default to assuming nscd runs.
495 If the PID is alive, assume it is running. That all unless
496 the PID is the same as the current process' since tha latter
497 can mean we re-exec. */
498 if ((n
!= 1 || kill (pid
, 0) == 0) && pid
!= getpid ())
505 /* Write the current process id to the file FILE.
506 Returns 0 if successful, -1 if not. */
508 write_pid (const char *file
)
512 fp
= fopen (file
, "w");
516 fprintf (fp
, "%d\n", getpid ());
518 int result
= fflush (fp
) || ferror (fp
) ? -1 : 0;