*/
#include "includes.h"
+#include "smbd/globals.h"
static_decl_rpc;
-static int am_parent = 1;
-
-extern struct auth_context *negprot_global_auth_context;
-extern SIG_ATOMIC_T got_sig_term;
-extern SIG_ATOMIC_T reload_after_sighup;
-static SIG_ATOMIC_T got_sig_cld;
-
#ifdef WITH_DFS
extern int dcelogin_atmost_once;
#endif /* WITH_DFS */
-/* really we should have a top level context structure that has the
- client file descriptor as an element. That would require a major rewrite :(
-
- the following 2 functions are an alternative - they make the file
- descriptor private to smbd
- */
-static int server_fd = -1;
-
int smbd_server_fd(void)
{
return server_fd;
struct event_context *smbd_event_context(void)
{
- static struct event_context *ctx;
-
- if (!ctx && !(ctx = event_context_init(NULL))) {
+ if (!smbd_event_ctx) {
+ smbd_event_ctx = event_context_init(talloc_autofree_context());
+ }
+ if (!smbd_event_ctx) {
smb_panic("Could not init smbd event context");
}
- return ctx;
+ return smbd_event_ctx;
}
struct messaging_context *smbd_messaging_context(void)
{
- static struct messaging_context *ctx;
-
- if (!ctx && !(ctx = messaging_init(NULL, server_id_self(),
- smbd_event_context()))) {
- smb_panic("Could not init smbd messaging context");
+ if (smbd_msg_ctx == NULL) {
+ smbd_msg_ctx = messaging_init(talloc_autofree_context(),
+ server_id_self(),
+ smbd_event_context());
+ }
+ if (smbd_msg_ctx == NULL) {
+ DEBUG(0, ("Could not init smbd messaging context.\n"));
}
- return ctx;
+ return smbd_msg_ctx;
}
struct memcache *smbd_memcache(void)
{
- static struct memcache *cache;
-
- if (!cache
- && !(cache = memcache_init(NULL,
- lp_max_stat_cache_size()*1024))) {
-
+ if (!smbd_memcache_ctx) {
+ smbd_memcache_ctx = memcache_init(talloc_autofree_context(),
+ lp_max_stat_cache_size()*1024);
+ }
+ if (!smbd_memcache_ctx) {
smb_panic("Could not init smbd memcache");
}
- return cache;
+
+ return smbd_memcache_ctx;
}
/*******************************************************************
stat_cache_delete(name);
}
-/****************************************************************************
- Terminate signal.
-****************************************************************************/
-
-static void sig_term(void)
-{
- got_sig_term = 1;
- sys_select_signal(SIGTERM);
-}
-
-/****************************************************************************
- Catch a sighup.
-****************************************************************************/
-
-static void sig_hup(int sig)
-{
- reload_after_sighup = 1;
- sys_select_signal(SIGHUP);
-}
-
-/****************************************************************************
- Catch a sigcld
-****************************************************************************/
-static void sig_cld(int sig)
-{
- got_sig_cld = 1;
- sys_select_signal(SIGCLD);
-}
-
/****************************************************************************
Send a SIGTERM to our process group.
*****************************************************************************/
/* close our standard file descriptors */
close_low_fds(False); /* Don't close stderr */
-
- set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
- set_socket_options(smbd_server_fd(), lp_socket_options());
return True;
}
pid_t pid;
};
-static struct child_pid *children;
-static int num_children;
-
static void add_child_pid(pid_t pid)
{
struct child_pid *child;
/* a child terminated uncleanly so tickle all processes to see
if they can grab any of the pending locks
*/
+ DEBUG(3,(__location__ " Unclean shutdown of pid %u\n", pid));
messaging_send_buf(smbd_messaging_context(), procid_self(),
MSG_SMB_BRL_VALIDATE, NULL, 0);
message_send_all(smbd_messaging_context(),
return num_children < max_processes;
}
+static void smbd_sig_chld_handler(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data)
+{
+ pid_t pid;
+ int status;
+
+ while ((pid = sys_waitpid(-1, &status, WNOHANG)) > 0) {
+ bool unclean_shutdown = False;
+
+ /* If the child terminated normally, assume
+ it was an unclean shutdown unless the
+ status is 0
+ */
+ if (WIFEXITED(status)) {
+ unclean_shutdown = WEXITSTATUS(status);
+ }
+ /* If the child terminated due to a signal
+ we always assume it was unclean.
+ */
+ if (WIFSIGNALED(status)) {
+ unclean_shutdown = True;
+ }
+ remove_child_pid(pid, unclean_shutdown);
+ }
+}
+
+static void smbd_setup_sig_chld_handler(void)
+{
+ struct tevent_signal *se;
+
+ se = tevent_add_signal(smbd_event_context(),
+ smbd_event_context(),
+ SIGCHLD, 0,
+ smbd_sig_chld_handler,
+ NULL);
+ if (!se) {
+ exit_server("failed to setup SIGCHLD handler");
+ }
+}
+
/****************************************************************************
Open the socket communication.
****************************************************************************/
}
#ifdef HAVE_ATEXIT
- {
- static int atexit_set;
- if(atexit_set == 0) {
- atexit_set=1;
- atexit(killkids);
- }
- }
+ atexit(killkids);
#endif
/* Stop zombies */
- CatchSignal(SIGCLD, sig_cld);
+ smbd_setup_sig_chld_handler();
FD_ZERO(&listen_set);
const char *sock_ptr;
if (strequal(sock_addr, "0.0.0.0") ||
- strequal(sock_addr, "::")) {
+ strequal(sock_addr, "::")) {
#if HAVE_IPV6
sock_addr = "::,0.0.0.0";
#else
clustered mode, ctdb won't allow us to start doing database
operations until it has gone thru a full startup, which
includes checking to see that smbd is listening. */
- claim_connection(NULL,"",FLAG_MSG_GENERAL|FLAG_MSG_SMBD);
+ claim_connection(NULL,"",
+ FLAG_MSG_GENERAL|FLAG_MSG_SMBD|FLAG_MSG_DBWRAP);
/* Listen to messages */
MSG_SMB_STAT_CACHE_DELETE, smb_stat_cache_delete);
brl_register_msgs(smbd_messaging_context());
+#ifdef CLUSTER_SUPPORT
+ if (lp_clustering()) {
+ ctdbd_register_reconfigure(messaging_ctdbd_connection());
+ }
+#endif
+
#ifdef DEVELOPER
messaging_register(smbd_messaging_context(), NULL,
MSG_SMB_INJECT_FAULT, msg_inject_fault);
fd_set r_fds, w_fds;
int num;
- /* Ensure we respond to PING and DEBUG messages from the main smbd. */
- message_dispatch(smbd_messaging_context());
-
- if (got_sig_cld) {
- pid_t pid;
- int status;
-
- got_sig_cld = False;
-
- while ((pid = sys_waitpid(-1, &status, WNOHANG)) > 0) {
- bool unclean_shutdown = False;
-
- /* If the child terminated normally, assume
- it was an unclean shutdown unless the
- status is 0
- */
- if (WIFEXITED(status)) {
- unclean_shutdown = WEXITSTATUS(status);
- }
- /* If the child terminated due to a signal
- we always assume it was unclean.
- */
- if (WIFSIGNALED(status)) {
- unclean_shutdown = True;
- }
- remove_child_pid(pid, unclean_shutdown);
- }
+ if (run_events(smbd_event_context(), 0, NULL, NULL)) {
+ continue;
}
idle_timeout = timeval_zero();
timeval_is_zero(&idle_timeout) ?
NULL : &idle_timeout);
- if (num == -1 && errno == EINTR) {
- if (got_sig_term) {
- exit_server_cleanly(NULL);
- }
-
- /* check for sighup processing */
- if (reload_after_sighup) {
- change_to_root_user();
- DEBUG(1,("Reloading services after SIGHUP\n"));
- reload_services(False);
- reload_after_sighup = 0;
- }
-
+ if (run_events(smbd_event_context(), num, &r_fds, &w_fds)) {
continue;
}
-
/* If the idle timeout fired and we don't have any connected
* users, exit gracefully. We should be running under a process
--num;
}
- if (run_events(smbd_event_context(), num, &r_fds, &w_fds)) {
- continue;
- }
-
/* check if we need to reload services */
check_reload(time(NULL));
continue;
if (smbd_server_fd() == -1) {
- DEBUG(0,("open_sockets_smbd: accept: %s\n",
+ DEBUG(2,("open_sockets_smbd: accept: %s\n",
strerror(errno)));
continue;
}
- /* Ensure child is set to blocking mode */
- set_blocking(smbd_server_fd(),True);
-
- if (smbd_server_fd() != -1 && interactive)
+ if (interactive)
return True;
if (allowable_number_of_smbd_processes() &&
- smbd_server_fd() != -1 &&
((child = sys_fork())==0)) {
- char remaddr[INET6_ADDRSTRLEN];
-
/* Child code ... */
/* Stop zombies, the parent explicitly handles
close_low_fds(False);
am_parent = 0;
- set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
- set_socket_options(smbd_server_fd(),
- lp_socket_options());
-
- /* this is needed so that we get decent entries
- in smbstatus for port 445 connects */
- set_remote_machine_name(get_peer_addr(smbd_server_fd(),
- remaddr,
- sizeof(remaddr)),
- false);
-
- /* Reset the state of the random
- * number generation system, so
- * children do not get the same random
- * numbers as each other */
-
- set_need_random_reseed();
- /* tdb needs special fork handling - remove
- * CLEAR_IF_FIRST flags */
- if (tdb_reopen_all(1) == -1) {
- DEBUG(0,("tdb_reopen_all failed.\n"));
- smb_panic("tdb_reopen_all failed");
+ if (!reinit_after_fork(
+ smbd_messaging_context(),
+ smbd_event_context(),
+ true)) {
+ DEBUG(0,("reinit_after_fork() failed\n"));
+ smb_panic("reinit_after_fork() failed");
}
+ smbd_setup_sig_term_handler();
+ smbd_setup_sig_hup_handler();
+
return True;
}
/* The parent doesn't need this socket */
if (lp_loaded()) {
char *fname = lp_configfile();
- if (file_exist(fname, NULL) &&
+ if (file_exist(fname) &&
!strcsequal(fname, get_dyn_CONFIGFILE())) {
set_dyn_CONFIGFILE(fname);
test = False;
enum server_exit_reason { SERVER_EXIT_NORMAL, SERVER_EXIT_ABNORMAL };
static void exit_server_common(enum server_exit_reason how,
- const char *const reason) NORETURN_ATTRIBUTE;
+ const char *const reason) _NORETURN_;
static void exit_server_common(enum server_exit_reason how,
const char *const reason)
{
- static int firsttime=1;
+ bool had_open_conn;
- if (!firsttime)
+ if (!exit_firsttime)
exit(0);
- firsttime = 0;
+ exit_firsttime = false;
change_to_root_user();
(negprot_global_auth_context->free)(&negprot_global_auth_context);
}
- conn_close_all();
+ had_open_conn = conn_close_all();
invalidate_all_vuids();
}
#endif
+#ifdef USE_DMAPI
+ /* Destroy Samba DMAPI session only if we are master smbd process */
+ if (am_parent) {
+ if (!dmapi_destroy_session()) {
+ DEBUG(0,("Unable to close Samba DMAPI session\n"));
+ }
+ }
+#endif
+
locking_end();
printing_end();
(reason ? reason : "normal exit")));
}
- exit(0);
+ /* if we had any open SMB connections when we exited then we
+ need to tell the parent smbd so that it can trigger a retry
+ of any locks we may have been holding or open files we were
+ blocking */
+ if (had_open_conn) {
+ exit(1);
+ } else {
+ exit(0);
+ }
}
void exit_server(const char *const explanation)
exit_server("critical server fault");
}
-
-/****************************************************************************
-received when we should release a specific IP
-****************************************************************************/
-static void msg_release_ip(struct messaging_context *msg_ctx, void *private_data,
- uint32_t msg_type, struct server_id server_id, DATA_BLOB *data)
-{
- const char *ip = (const char *)data->data;
- char addr[INET6_ADDRSTRLEN];
-
- if (strcmp(client_socket_addr(get_client_fd(),addr,sizeof(addr)), ip) == 0) {
- /* we can't afford to do a clean exit - that involves
- database writes, which would potentially mean we
- are still running after the failover has finished -
- we have to get rid of this process ID straight
- away */
- DEBUG(0,("Got release IP message for our IP %s - exiting immediately\n",
- ip));
- _exit(0);
- }
-}
-
-
/****************************************************************************
Initialise connect, service and file structs.
****************************************************************************/
file_init();
- /* for RPC pipes */
- init_rpc_pipe_hnd();
-
init_dptrs();
- secrets_init();
-
- return True;
-}
-
-/*
- * Send keepalive packets to our client
- */
-static bool keepalive_fn(const struct timeval *now, void *private_data)
-{
- if (!send_keepalive(smbd_server_fd())) {
- DEBUG( 2, ( "Keepalive failed - exiting.\n" ) );
- return False;
- }
- return True;
-}
-
-/*
- * Do the recurring check if we're idle
- */
-static bool deadtime_fn(const struct timeval *now, void *private_data)
-{
- if ((conn_num_open() == 0)
- || (conn_idle_all(now->tv_sec))) {
- DEBUG( 2, ( "Closing idle connection\n" ) );
- messaging_send(smbd_messaging_context(), procid_self(),
- MSG_SHUTDOWN, &data_blob_null);
+ if (!secrets_init())
return False;
- }
return True;
}
-
/****************************************************************************
main program.
****************************************************************************/
int main(int argc,const char *argv[])
{
/* shall I run as a daemon */
- static bool is_daemon = False;
- static bool interactive = False;
- static bool Fork = True;
- static bool no_process_group = False;
- static bool log_stdout = False;
- static char *ports = NULL;
- static char *profile_level = NULL;
+ bool is_daemon = false;
+ bool interactive = false;
+ bool Fork = true;
+ bool no_process_group = false;
+ bool log_stdout = false;
+ char *ports = NULL;
+ char *profile_level = NULL;
int opt;
poptContext pc;
bool print_build_options = False;
};
TALLOC_CTX *frame = talloc_stackframe(); /* Setup tos. */
+ smbd_init_globals();
+
TimeInit();
#ifdef HAVE_SET_AUTH_PARAMETERS
fault_setup((void (*)(void *))exit_server_fault);
dump_core_setup("smbd");
- CatchSignal(SIGTERM , SIGNAL_CAST sig_term);
- CatchSignal(SIGHUP,SIGNAL_CAST sig_hup);
-
/* we are never interested in SIGPIPE */
BlockSignals(True,SIGPIPE);
reopen_logs();
- DEBUG(0,("smbd version %s started.\n", SAMBA_VERSION_STRING));
+ DEBUG(0,("smbd version %s started.\n", samba_version_string()));
DEBUGADD(0,("%s\n", COPYRIGHT_STARTUP_MESSAGE));
DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n",
exit(1);
}
- /*
- * Do this before reload_services.
- */
+ if (!lp_load_initial_only(get_dyn_CONFIGFILE())) {
+ DEBUG(0, ("error opening config file\n"));
+ exit(1);
+ }
+
+ if (smbd_messaging_context() == NULL)
+ exit(1);
if (!reload_services(False))
return(-1);
setpgid( (pid_t)0, (pid_t)0);
#endif
- if (!directory_exist(lp_lockdir(), NULL))
+ if (!directory_exist(lp_lockdir()))
mkdir(lp_lockdir(), 0755);
if (is_daemon)
pidfile_create("smbd");
- /* Setup all the TDB's - including CLEAR_IF_FIRST tdb's. */
-
- if (smbd_messaging_context() == NULL)
+ if (!reinit_after_fork(smbd_messaging_context(),
+ smbd_event_context(), false)) {
+ DEBUG(0,("reinit_after_fork() failed\n"));
exit(1);
+ }
+
+ smbd_setup_sig_term_handler();
+ smbd_setup_sig_hup_handler();
+
+ /* Setup all the TDB's - including CLEAR_IF_FIRST tdb's. */
if (smbd_memcache() == NULL) {
exit(1);
namecache_enable();
- if (!init_registry())
+ if (!W_ERROR_IS_OK(registry_init_full()))
exit(1);
#if 0
smbd is launched via inetd and we fork a copy of
ourselves here */
- if ( is_daemon && !interactive )
- start_background_queue();
-
- /* Always attempt to initialize DMAPI. We will only use it later if
- * lp_dmapi_support is set on the share, but we need a single global
- * session to work with.
- */
- dmapi_init_session();
-
- if (!open_sockets_smbd(is_daemon, interactive, ports))
- exit(1);
-
- /*
- * everything after this point is run after the fork()
- */
-
- static_init_rpc;
-
- init_modules();
-
- /* Possibly reload the services file. Only worth doing in
- * daemon mode. In inetd mode, we know we only just loaded this.
- */
- if (is_daemon) {
- reload_services(True);
+ if (is_daemon && !interactive
+ && lp_parm_bool(-1, "smbd", "backgroundqueue", true)) {
+ start_background_queue();
}
- if (!init_account_policy()) {
- DEBUG(0,("Could not open account policy tdb.\n"));
- exit(1);
- }
-
- if (*lp_rootdir()) {
- if (sys_chroot(lp_rootdir()) == 0)
- DEBUG(2,("Changed root to %s\n", lp_rootdir()));
- }
-
- /* Setup oplocks */
- if (!init_oplocks(smbd_messaging_context()))
- exit(1);
-
- /* Setup aio signal handler. */
- initialize_async_io_handler();
-
- /*
- * For clustering, we need to re-init our ctdbd connection after the
- * fork
- */
- if (!NT_STATUS_IS_OK(messaging_reinit(smbd_messaging_context())))
- exit(1);
-
- /* register our message handlers */
- messaging_register(smbd_messaging_context(), NULL,
- MSG_SMB_FORCE_TDIS, msg_force_tdis);
- messaging_register(smbd_messaging_context(), NULL,
- MSG_SMB_RELEASE_IP, msg_release_ip);
-
- if ((lp_keepalive() != 0)
- && !(event_add_idle(smbd_event_context(), NULL,
- timeval_set(lp_keepalive(), 0),
- "keepalive", keepalive_fn,
- NULL))) {
- DEBUG(0, ("Could not add keepalive event\n"));
- exit(1);
- }
-
- if (!(event_add_idle(smbd_event_context(), NULL,
- timeval_set(IDLE_CLOSED_TIMEOUT, 0),
- "deadtime", deadtime_fn, NULL))) {
- DEBUG(0, ("Could not add deadtime event\n"));
+ if (!open_sockets_smbd(is_daemon, interactive, ports))
exit(1);
- }
TALLOC_FREE(frame);
smbd_process();
- namecache_shutdown();
-
exit_server_cleanly(NULL);
return(0);
}