smbd: Remove source3/smbd/statcache.c
[samba.git] / source3 / smbd / server.c
index 871bb9234491c6866f2a794010db418f0ca5a200..6bdaca7a0a410286be5ac3cc9aa335c1eee9b77c 100644 (file)
 #include "includes.h"
 #include "system/filesys.h"
 #include "lib/util/server_id.h"
-#include "popt_common.h"
+#include "lib/util/close_low_fd.h"
+#include "lib/cmdline/cmdline.h"
+#include "locking/share_mode_lock.h"
 #include "smbd/smbd.h"
 #include "smbd/globals.h"
+#include "smbd/smbXsrv_open.h"
 #include "registry/reg_init_full.h"
 #include "libcli/auth/schannel.h"
 #include "secrets.h"
 #include "../lib/util/memcache.h"
 #include "ctdbd_conn.h"
+#include "lib/util/util_process.h"
 #include "util_cluster.h"
 #include "printing/queue_process.h"
-#include "rpc_server/rpc_service_setup.h"
 #include "rpc_server/rpc_config.h"
 #include "passdb.h"
 #include "auth.h"
@@ -44,7 +47,6 @@
 #include "lib/id_cache.h"
 #include "lib/param/param.h"
 #include "lib/background.h"
-#include "lib/conn_tdb.h"
 #include "../lib/util/pidfile.h"
 #include "lib/smbd_shim.h"
 #include "scavenger.h"
@@ -54,6 +56,8 @@
 #include "lib/util/sys_rw.h"
 #include "cleanupdb.h"
 #include "g_lock.h"
+#include "lib/global_contexts.h"
+#include "source3/lib/substitute.h"
 
 #ifdef CLUSTER_SUPPORT
 #include "ctdb_protocol.h"
@@ -93,51 +97,31 @@ struct smbd_child_pid {
        pid_t pid;
 };
 
-extern void start_epmd(struct tevent_context *ev_ctx,
-                      struct messaging_context *msg_ctx);
-
-extern void start_lsasd(struct tevent_context *ev_ctx,
-                       struct messaging_context *msg_ctx);
-
-extern void start_fssd(struct tevent_context *ev_ctx,
-                      struct messaging_context *msg_ctx);
-
-extern void start_mdssd(struct tevent_context *ev_ctx,
-                       struct messaging_context *msg_ctx);
-
 /*******************************************************************
  What to do when smb.conf is updated.
  ********************************************************************/
 
+static NTSTATUS messaging_send_to_children(struct messaging_context *msg_ctx,
+                                          uint32_t msg_type, DATA_BLOB* data);
+
 static void smbd_parent_conf_updated(struct messaging_context *msg,
                                     void *private_data,
                                     uint32_t msg_type,
                                     struct server_id server_id,
                                     DATA_BLOB *data)
 {
-       struct tevent_context *ev_ctx =
-               talloc_get_type_abort(private_data, struct tevent_context);
+       bool ok;
 
        DEBUG(10,("smbd_parent_conf_updated: Got message saying smb.conf was "
                  "updated. Reloading.\n"));
        change_to_root_user();
        reload_services(NULL, NULL, false);
-       printing_subsystem_update(ev_ctx, msg, false);
-}
-
-/*******************************************************************
- Delete a statcache entry.
- ********************************************************************/
 
-static void smb_stat_cache_delete(struct messaging_context *msg,
-                                 void *private_data,
-                                 uint32_t msg_tnype,
-                                 struct server_id server_id,
-                                 DATA_BLOB *data)
-{
-       const char *name = (const char *)data->data;
-       DEBUG(10,("smb_stat_cache_delete: delete name %s\n", name));
-       stat_cache_delete(name);
+       ok = reinit_guest_session_info(NULL);
+       if (!ok) {
+               DBG_ERR("Failed to reinit guest info\n");
+       }
+       messaging_send_to_children(msg, MSG_SMB_CONF_UPDATED, NULL);
 }
 
 /****************************************************************************
@@ -303,31 +287,6 @@ static void smbd_parent_id_cache_delete(struct messaging_context *ctx,
        messaging_send_to_children(ctx, msg_type, msg_data);
 }
 
-#ifdef CLUSTER_SUPPORT
-static int smbd_parent_ctdb_reconfigured(
-       struct tevent_context *ev,
-       uint32_t src_vnn, uint32_t dst_vnn, uint64_t dst_srvid,
-       const uint8_t *msg, size_t msglen, void *private_data)
-{
-       struct messaging_context *msg_ctx = talloc_get_type_abort(
-               private_data, struct messaging_context);
-
-       DEBUG(10, ("Got %s message\n", (dst_srvid == CTDB_SRVID_RECONFIGURE)
-                  ? "cluster reconfigure" : "SAMBA_NOTIFY"));
-
-       /*
-        * Someone from the family died, validate our locks
-        */
-
-       if (am_parent) {
-               messaging_send_buf(msg_ctx, am_parent->cleanupd,
-                                  MSG_SMB_BRL_VALIDATE, NULL, 0);
-       }
-
-       return 0;
-}
-#endif
-
 static void add_child_pid(struct smbd_parent_context *parent,
                          pid_t pid)
 {
@@ -413,11 +372,24 @@ static void notifyd_stopped(struct tevent_req *req)
        DEBUG(1, ("notifyd stopped: %s\n", strerror(ret)));
 }
 
+static void notifyd_sig_hup_handler(struct tevent_context *ev,
+                                   struct tevent_signal *se,
+                                   int signum,
+                                   int count,
+                                   void *siginfo,
+                                   void *pvt)
+{
+       DBG_NOTICE("notifyd: Reloading services after SIGHUP\n");
+       reload_services(NULL, NULL, false);
+       reopen_logs();
+}
+
 static bool smbd_notifyd_init(struct messaging_context *msg, bool interactive,
                              struct server_id *ppid)
 {
        struct tevent_context *ev = messaging_tevent_context(msg);
        struct tevent_req *req;
+       struct tevent_signal *se = NULL;
        pid_t pid;
        NTSTATUS status;
        bool ok;
@@ -435,20 +407,35 @@ static bool smbd_notifyd_init(struct messaging_context *msg, bool interactive,
        }
 
        if (pid != 0) {
-               if (am_parent != 0) {
+               if (am_parent != NULL) {
                        add_child_pid(am_parent, pid);
                }
                *ppid = pid_to_procid(pid);
                return true;
        }
 
-       status = smbd_reinit_after_fork(msg, ev, true, "smbd-notifyd");
+       status = smbd_reinit_after_fork(msg, ev, true);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("%s: reinit_after_fork failed: %s\n",
                          __func__, nt_errstr(status)));
                exit(1);
        }
 
+       process_set_title("smbd-notifyd", "notifyd");
+
+       reopen_logs();
+
+       /* Set up sighup handler for notifyd */
+       se = tevent_add_signal(ev,
+                              ev,
+                              SIGHUP, 0,
+                              notifyd_sig_hup_handler,
+                              NULL);
+       if (!se) {
+               DEBUG(0, ("failed to setup notifyd SIGHUP handler\n"));
+               exit(1);
+       }
+
        req = notifyd_req(msg, ev);
        if (req == NULL) {
                exit(1);
@@ -456,7 +443,6 @@ static bool smbd_notifyd_init(struct messaging_context *msg, bool interactive,
        tevent_req_set_callback(req, notifyd_stopped, msg);
 
        /* Block those signals that we are not handling */
-       BlockSignals(True, SIGHUP);
        BlockSignals(True, SIGUSR1);
 
        messaging_send(msg, pid_to_procid(getppid()), MSG_SMB_NOTIFY_STARTED,
@@ -565,6 +551,17 @@ static void notifyd_started(struct tevent_req *req)
        }
 }
 
+static void cleanupd_sig_hup_handler(struct tevent_context *ev,
+                                    struct tevent_signal *se,
+                                    int signum,
+                                    int count,
+                                    void *siginfo,
+                                    void *pvt)
+{
+       DBG_NOTICE("cleanupd: Reloading services after SIGHUP\n");
+       reopen_logs();
+}
+
 static void cleanupd_stopped(struct tevent_req *req);
 
 static bool cleanupd_init(struct messaging_context *msg, bool interactive,
@@ -572,6 +569,7 @@ static bool cleanupd_init(struct messaging_context *msg, bool interactive,
 {
        struct tevent_context *ev = messaging_tevent_context(msg);
        struct server_id parent_id = messaging_server_id(msg);
+       struct tevent_signal *se = NULL;
        struct tevent_req *req;
        pid_t pid;
        NTSTATUS status;
@@ -632,7 +630,7 @@ static bool cleanupd_init(struct messaging_context *msg, bool interactive,
 
        close(up_pipe[0]);
 
-       status = smbd_reinit_after_fork(msg, ev, true, "cleanupd");
+       status = smbd_reinit_after_fork(msg, ev, true);
        if (!NT_STATUS_IS_OK(status)) {
                DBG_WARNING("reinit_after_fork failed: %s\n",
                            nt_errstr(status));
@@ -642,6 +640,19 @@ static bool cleanupd_init(struct messaging_context *msg, bool interactive,
                exit(1);
        }
 
+       process_set_title("smbd-cleanupd", "cleanupd");
+
+       se = tevent_add_signal(ev,
+                              ev,
+                              SIGHUP,
+                              0,
+                              cleanupd_sig_hup_handler,
+                              NULL);
+       if (se == NULL) {
+               DBG_ERR("Could not add SIGHUP handler\n");
+               exit(1);
+       }
+
        req = smbd_cleanupd_send(msg, ev, msg, parent_id.pid);
        if (req == NULL) {
                DBG_WARNING("smbd_cleanupd_send failed\n");
@@ -764,32 +775,6 @@ static bool cleanupd_init_recv(struct tevent_req *req)
        return state->ok;
 }
 
-/*
-  at most every smbd:cleanuptime seconds (default 20), we scan the BRL
-  and locking database for entries to cleanup. As a side effect this
-  also cleans up dead entries in the connections database (due to the
-  traversal in message_send_all()
-
-  Using a timer for this prevents a flood of traversals when a large
-  number of clients disconnect at the same time (perhaps due to a
-  network outage).  
-*/
-
-static void cleanup_timeout_fn(struct tevent_context *event_ctx,
-                               struct tevent_timer *te,
-                               struct timeval now,
-                               void *private_data)
-{
-       struct smbd_parent_context *parent =
-               talloc_get_type_abort(private_data,
-               struct smbd_parent_context);
-
-       parent->cleanup_te = NULL;
-
-       messaging_send_buf(parent->msg_ctx, parent->cleanupd,
-                          MSG_SMB_BRL_VALIDATE, NULL, 0);
-}
-
 static void cleanupd_started(struct tevent_req *req)
 {
        bool ok;
@@ -892,25 +877,6 @@ static void remove_child_pid(struct smbd_parent_context *parent,
                                nt_errstr(status));
                }
        }
-
-       if (unclean_shutdown) {
-               /* 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",
-                       (unsigned int)pid));
-               if (parent->cleanup_te == NULL) {
-                       /* call the cleanup timer, but not too often */
-                       int cleanup_time = lp_parm_int(-1, "smbd", "cleanuptime", 20);
-                       parent->cleanup_te = tevent_add_timer(parent->ev_ctx,
-                                               parent,
-                                               timeval_current_ofs(cleanup_time, 0),
-                                               cleanup_timeout_fn,
-                                               parent);
-                       DEBUG(1,("Scheduled cleanup of brl and lock database after unclean shutdown\n"));
-               }
-       }
 }
 
 /****************************************************************************
@@ -1008,7 +974,7 @@ static void smbd_accept_connection(struct tevent_context *ev,
        smb_set_close_on_exec(fd);
 
        if (s->parent->interactive) {
-               reinit_after_fork(msg_ctx, ev, true, NULL);
+               reinit_after_fork(msg_ctx, ev, true);
                smbd_process(ev, msg_ctx, fd, true);
                exit_server_cleanly("end of interactive mode");
                return;
@@ -1021,6 +987,7 @@ static void smbd_accept_connection(struct tevent_context *ev,
 
        pid = fork();
        if (pid == 0) {
+               char addrstr[INET6_ADDRSTRLEN];
                NTSTATUS status = NT_STATUS_OK;
 
                /*
@@ -1034,7 +1001,7 @@ static void smbd_accept_connection(struct tevent_context *ev,
                 * them, counting worker smbds. */
                CatchChild();
 
-               status = smbd_reinit_after_fork(msg_ctx, ev, true, NULL);
+               status = smbd_reinit_after_fork(msg_ctx, ev, true);
                if (!NT_STATUS_IS_OK(status)) {
                        if (NT_STATUS_EQUAL(status,
                                            NT_STATUS_TOO_MANY_OPENED_FILES)) {
@@ -1058,6 +1025,9 @@ static void smbd_accept_connection(struct tevent_context *ev,
                        smb_panic("reinit_after_fork() failed");
                }
 
+               print_sockaddr(addrstr, sizeof(addrstr), &addr);
+               process_set_title("smbd[%s]", "client [%s]", addrstr);
+
                smbd_process(ev, msg_ctx, fd, false);
         exit:
                exit_server_cleanly("end of child");
@@ -1091,7 +1061,7 @@ static void smbd_accept_connection(struct tevent_context *ev,
         * writes only two messages for each child
         * started/finished. But each child writes,
         * say, 50 messages also in logserver.smb,
-        * begining with the debug_count of the
+        * beginning with the debug_count of the
         * parent, before the child opens its own log
         * file logserver.client. In a worst case
         * scenario the size of logserver.smb would be
@@ -1114,14 +1084,11 @@ static bool smbd_open_one_socket(struct smbd_parent_context *parent,
        }
 
        s->parent = parent;
-       s->fd = open_socket_in(SOCK_STREAM,
-                              port,
-                              parent->sockets == NULL ? 0 : 2,
-                              ifss,
-                              true);
-       if (s->fd == -1) {
-               DEBUG(0,("smbd_open_one_socket: open_socket_in: "
-                       "%s\n", strerror(errno)));
+
+       s->fd = open_socket_in(SOCK_STREAM, ifss, port, true);
+       if (s->fd < 0) {
+               int err = -(s->fd);
+               DBG_ERR("open_socket_in failed: %s\n", strerror(err));
                TALLOC_FREE(s);
                /*
                 * We ignore an error here, as we've done before
@@ -1298,11 +1265,11 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
        messaging_register(msg_ctx, NULL, MSG_SHUTDOWN, msg_exit_server);
        messaging_register(msg_ctx, ev_ctx, MSG_SMB_CONF_UPDATED,
                           smbd_parent_conf_updated);
-       messaging_register(msg_ctx, NULL, MSG_SMB_STAT_CACHE_DELETE,
-                          smb_stat_cache_delete);
        messaging_register(msg_ctx, NULL, MSG_DEBUG, smbd_msg_debug);
        messaging_register(msg_ctx, NULL, MSG_SMB_FORCE_TDIS,
                           smb_parent_send_to_children);
+       messaging_register(msg_ctx, NULL, MSG_SMB_FORCE_TDIS_DENIED,
+                          smb_parent_send_to_children);
        messaging_register(msg_ctx, NULL, MSG_SMB_KILL_CLIENT_IP,
                           smb_parent_send_to_children);
        messaging_register(msg_ctx, NULL, MSG_SMB_TELL_NUM_CHILDREN,
@@ -1315,17 +1282,6 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
        messaging_register(msg_ctx, NULL, MSG_SMB_NOTIFY_STARTED,
                           smb_parent_send_to_children);
 
-#ifdef CLUSTER_SUPPORT
-       if (lp_clustering()) {
-               struct ctdbd_connection *conn = messaging_ctdb_connection();
-
-               register_with_ctdbd(conn, CTDB_SRVID_RECONFIGURE,
-                                   smbd_parent_ctdb_reconfigured, msg_ctx);
-               register_with_ctdbd(conn, CTDB_SRVID_SAMBA_NOTIFY,
-                                   smbd_parent_ctdb_reconfigured, msg_ctx);
-       }
-#endif
-
 #ifdef DEVELOPER
        messaging_register(msg_ctx, NULL, MSG_SMB_INJECT_FAULT,
                           msg_inject_fault);
@@ -1437,9 +1393,6 @@ static bool init_structs(void )
         * set from the config file.
         */
 
-       if (!init_names())
-               return False;
-
        if (!secrets_init())
                return False;
 
@@ -1463,15 +1416,9 @@ static void smbd_parent_sig_hup_handler(struct tevent_context *ev,
                                        void *siginfo,
                                        void *private_data)
 {
-       struct smbd_parent_context *parent =
-               talloc_get_type_abort(private_data,
-               struct smbd_parent_context);
-
        change_to_root_user();
        DEBUG(1,("parent: Reloading services after SIGHUP\n"));
        reload_services(NULL, NULL, false);
-
-       printing_subsystem_update(parent->ev_ctx, parent->msg_ctx, true);
 }
 
 struct smbd_claim_version_state {
@@ -1479,8 +1426,9 @@ struct smbd_claim_version_state {
        char *version;
 };
 
-static void smbd_claim_version_parser(const struct g_lock_rec *locks,
-                                     size_t num_locks,
+static void smbd_claim_version_parser(struct server_id exclusive,
+                                     size_t num_shared,
+                                     const struct server_id *shared,
                                      const uint8_t *data,
                                      size_t datalen,
                                      void *private_data)
@@ -1504,6 +1452,7 @@ static NTSTATUS smbd_claim_version(struct messaging_context *msg,
                                   const char *version)
 {
        const char *name = "samba_version_string";
+       const TDB_DATA key = string_term_tdb_data(name);
        struct smbd_claim_version_state state;
        struct g_lock_ctx *ctx;
        NTSTATUS status;
@@ -1514,8 +1463,12 @@ static NTSTATUS smbd_claim_version(struct messaging_context *msg,
                return NT_STATUS_UNSUCCESSFUL;
        }
 
-       status = g_lock_lock(ctx, string_term_tdb_data(name), G_LOCK_READ,
-                            (struct timeval) { .tv_sec = 60 });
+       status = g_lock_lock(ctx,
+                            key,
+                            G_LOCK_READ,
+                            (struct timeval) { .tv_sec = 60 },
+                            NULL,
+                            NULL);
        if (!NT_STATUS_IS_OK(status)) {
                DBG_WARNING("g_lock_lock(G_LOCK_READ) failed: %s\n",
                            nt_errstr(status));
@@ -1525,12 +1478,11 @@ static NTSTATUS smbd_claim_version(struct messaging_context *msg,
 
        state = (struct smbd_claim_version_state) { .mem_ctx = ctx };
 
-       status = g_lock_dump(ctx, string_term_tdb_data(name),
-                            smbd_claim_version_parser, &state);
+       status = g_lock_dump(ctx, key, smbd_claim_version_parser, &state);
        if (!NT_STATUS_IS_OK(status) &&
            !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
                DBG_ERR("Could not read samba_version_string\n");
-               g_lock_unlock(ctx, string_term_tdb_data(name));
+               g_lock_unlock(ctx, key);
                TALLOC_FREE(ctx);
                return status;
        }
@@ -1544,8 +1496,12 @@ static NTSTATUS smbd_claim_version(struct messaging_context *msg,
                return NT_STATUS_OK;
        }
 
-       status = g_lock_lock(ctx, string_term_tdb_data(name), G_LOCK_WRITE,
-                            (struct timeval) { .tv_sec = 60 });
+       status = g_lock_lock(ctx,
+                            key,
+                            G_LOCK_UPGRADE,
+                            (struct timeval) { .tv_sec = 60 },
+                            NULL,
+                            NULL);
        if (!NT_STATUS_IS_OK(status)) {
                DBG_WARNING("g_lock_lock(G_LOCK_WRITE) failed: %s\n",
                            nt_errstr(status));
@@ -1555,9 +1511,8 @@ static NTSTATUS smbd_claim_version(struct messaging_context *msg,
                return NT_STATUS_SXS_VERSION_CONFLICT;
        }
 
-       status = g_lock_write_data(ctx, string_term_tdb_data(name),
-                                  (const uint8_t *)version,
-                                  strlen(version)+1);
+       status = g_lock_write_data(
+               ctx, key, (const uint8_t *)version, strlen(version)+1);
        if (!NT_STATUS_IS_OK(status)) {
                DBG_WARNING("g_lock_write_data failed: %s\n",
                            nt_errstr(status));
@@ -1565,8 +1520,12 @@ static NTSTATUS smbd_claim_version(struct messaging_context *msg,
                return status;
        }
 
-       status = g_lock_lock(ctx, string_term_tdb_data(name), G_LOCK_READ,
-                            (struct timeval) { .tv_sec = 60 });
+       status = g_lock_lock(ctx,
+                            key,
+                            G_LOCK_DOWNGRADE,
+                            (struct timeval) { .tv_sec = 60 },
+                            NULL,
+                            NULL);
        if (!NT_STATUS_IS_OK(status)) {
                DBG_WARNING("g_lock_lock(G_LOCK_READ) failed: %s\n",
                            nt_errstr(status));
@@ -1593,36 +1552,43 @@ extern void build_options(bool screen);
  int main(int argc,const char *argv[])
 {
        /* shall I run as a daemon */
-       bool is_daemon = false;
-       bool interactive = false;
-       bool Fork = true;
-       bool no_process_group = false;
+       struct samba_cmdline_daemon_cfg *cmdline_daemon_cfg = NULL;
        bool log_stdout = false;
        char *ports = NULL;
        char *profile_level = NULL;
        int opt;
        poptContext pc;
-       bool print_build_options = False;
        struct server_id main_server_id = {0};
-        enum {
-               OPT_DAEMON = 1000,
-               OPT_INTERACTIVE,
-               OPT_FORK,
-               OPT_NO_PROCESS_GROUP,
-               OPT_LOG_STDOUT
-       };
        struct poptOption long_options[] = {
-       POPT_AUTOHELP
-       {"daemon", 'D', POPT_ARG_NONE, NULL, OPT_DAEMON, "Become a daemon (default)" },
-       {"interactive", 'i', POPT_ARG_NONE, NULL, OPT_INTERACTIVE, "Run interactive (not a daemon) and log to stdout"},
-       {"foreground", 'F', POPT_ARG_NONE, NULL, OPT_FORK, "Run daemon in foreground (for daemontools, etc.)" },
-       {"no-process-group", '\0', POPT_ARG_NONE, NULL, OPT_NO_PROCESS_GROUP, "Don't create a new process group" },
-       {"log-stdout", 'S', POPT_ARG_NONE, NULL, OPT_LOG_STDOUT, "Log to stdout" },
-       {"build-options", 'b', POPT_ARG_NONE, NULL, 'b', "Print build options" },
-       {"port", 'p', POPT_ARG_STRING, &ports, 0, "Listen on the specified ports"},
-       {"profiling-level", 'P', POPT_ARG_STRING, &profile_level, 0, "Set profiling level","PROFILE_LEVEL"},
-       POPT_COMMON_SAMBA
-       POPT_TABLEEND
+               POPT_AUTOHELP
+               {
+                       .longName   = "build-options",
+                       .shortName  = 'b',
+                       .argInfo    = POPT_ARG_NONE,
+                       .arg        = NULL,
+                       .val        = 'b',
+                       .descrip    = "Print build options" ,
+               },
+               {
+                       .longName   = "port",
+                       .shortName  = 'p',
+                       .argInfo    = POPT_ARG_STRING,
+                       .arg        = &ports,
+                       .val        = 0,
+                       .descrip    = "Listen on the specified ports",
+               },
+               {
+                       .longName   = "profiling-level",
+                       .shortName  = 'P',
+                       .argInfo    = POPT_ARG_STRING,
+                       .arg        = &profile_level,
+                       .val        = 0,
+                       .descrip    = "Set profiling level","PROFILE_LEVEL",
+               },
+               POPT_COMMON_SAMBA
+               POPT_COMMON_DAEMON
+               POPT_COMMON_VERSION
+               POPT_TABLEEND
        };
        struct smbd_parent_context *parent = NULL;
        TALLOC_CTX *frame;
@@ -1633,10 +1599,10 @@ extern void build_options(bool screen);
        struct tevent_signal *se;
        int profiling_level;
        char *np_dir = NULL;
+       const struct loadparm_substitution *lp_sub =
+               loadparm_s3_global_substitution();
        static const struct smbd_shim smbd_shim_fns =
        {
-               .cancel_pending_lock_requests_by_fid = smbd_cancel_pending_lock_requests_by_fid,
-               .send_stat_cache_delete_message = smbd_send_stat_cache_delete_message,
                .change_to_root_user = smbd_change_to_root_user,
                .become_authenticated_pipe_user = smbd_become_authenticated_pipe_user,
                .unbecome_authenticated_pipe_user = smbd_unbecome_authenticated_pipe_user,
@@ -1650,6 +1616,9 @@ extern void build_options(bool screen);
                .exit_server = smbd_exit_server,
                .exit_server_cleanly = smbd_exit_server_cleanly,
        };
+       bool ok;
+
+       setproctitle_init(argc, discard_const(argv), environ);
 
        /*
         * Do this before any other talloc operation
@@ -1657,8 +1626,6 @@ extern void build_options(bool screen);
        talloc_enable_null_tracking();
        frame = talloc_stackframe();
 
-       setup_logging(argv[0], DEBUG_DEFAULT_STDOUT);
-
        smb_init_locale();
 
        set_smbd_shim(&smbd_shim_fns);
@@ -1671,26 +1638,31 @@ extern void build_options(bool screen);
        set_auth_parameters(argc,argv);
 #endif
 
-       pc = poptGetContext("smbd", argc, argv, long_options, 0);
+       ok = samba_cmdline_init(frame,
+                               SAMBA_CMDLINE_CONFIG_SERVER,
+                               true /* require_smbconf */);
+       if (!ok) {
+               DBG_ERR("Failed to setup cmdline parser!\n");
+               exit(ENOMEM);
+       }
+
+       cmdline_daemon_cfg = samba_cmdline_get_daemon_cfg();
+
+       pc = samba_popt_get_context(getprogname(),
+                                   argc,
+                                   argv,
+                                   long_options,
+                                   0);
+       if (pc == NULL) {
+               DBG_ERR("Failed to get popt context!\n");
+               exit(ENOMEM);
+       }
+
        while((opt = poptGetNextOpt(pc)) != -1) {
                switch (opt)  {
-               case OPT_DAEMON:
-                       is_daemon = true;
-                       break;
-               case OPT_INTERACTIVE:
-                       interactive = true;
-                       break;
-               case OPT_FORK:
-                       Fork = false;
-                       break;
-               case OPT_NO_PROCESS_GROUP:
-                       no_process_group = true;
-                       break;
-               case OPT_LOG_STDOUT:
-                       log_stdout = true;
-                       break;
                case 'b':
-                       print_build_options = True;
+                       build_options(true); /* Display output to screen as well as debug */
+                       exit(0);
                        break;
                default:
                        d_fprintf(stderr, "\nInvalid option %s: %s\n\n",
@@ -1701,20 +1673,10 @@ extern void build_options(bool screen);
        }
        poptFreeContext(pc);
 
-       if (interactive) {
-               Fork = False;
-               log_stdout = True;
-       }
+       log_stdout = (debug_get_log_type() == DEBUG_STDOUT);
 
-       if (log_stdout) {
-               setup_logging(argv[0], DEBUG_STDOUT);
-       } else {
-               setup_logging(argv[0], DEBUG_FILE);
-       }
-
-       if (print_build_options) {
-               build_options(True); /* Display output to screen as well as debug */
-               exit(0);
+        if (cmdline_daemon_cfg->interactive) {
+               log_stdout = True;
        }
 
 #ifdef HAVE_SETLUID
@@ -1724,11 +1686,11 @@ extern void build_options(bool screen);
 
        set_remote_machine_name("smbd", False);
 
-       if (interactive && (DEBUGLEVEL >= 9)) {
+       if (cmdline_daemon_cfg->interactive && (DEBUGLEVEL >= 9)) {
                talloc_enable_leak_report();
        }
 
-       if (log_stdout && Fork) {
+       if (log_stdout && cmdline_daemon_cfg->fork) {
                DEBUG(0,("ERROR: Can't log to stdout (-S) unless daemon is in foreground (-F) or interactive (-i)\n"));
                exit(1);
        }
@@ -1746,8 +1708,7 @@ extern void build_options(bool screen);
        gain_root_privilege();
        gain_root_group_privilege();
 
-       fault_setup();
-       dump_core_setup("smbd", lp_logfile(talloc_tos()));
+       dump_core_setup("smbd", lp_logfile(talloc_tos(), lp_sub));
 
        /* we are never interested in SIGPIPE */
        BlockSignals(True,SIGPIPE);
@@ -1762,8 +1723,11 @@ extern void build_options(bool screen);
        BlockSignals(True,SIGUSR2);
 #endif
 
-       /* POSIX demands that signals are inherited. If the invoking process has
-        * these signals masked, we will have problems, as we won't recieve them. */
+       /*
+        * POSIX demands that signals are inherited. If the invoking
+        * process has these signals masked, we will have problems, as
+        * we won't receive them.
+        */
        BlockSignals(False, SIGHUP);
        BlockSignals(False, SIGUSR1);
        BlockSignals(False, SIGTERM);
@@ -1785,7 +1749,7 @@ extern void build_options(bool screen);
        DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n",
                 (int)getuid(),(int)getgid(),(int)geteuid(),(int)getegid()));
 
-       /* Output the build options to the debug log */ 
+       /* Output the build options to the debug log */
        build_options(False);
 
        if (sizeof(uint16_t) < 2 || sizeof(uint32_t) < 4) {
@@ -1793,10 +1757,12 @@ extern void build_options(bool screen);
                exit(1);
        }
 
-       if (!lp_load_initial_only(get_dyn_CONFIGFILE())) {
-               DEBUG(0, ("error opening config file '%s'\n", get_dyn_CONFIGFILE()));
-               exit(1);
-       }
+       /*
+        * This calls unshare(CLONE_FS); on linux
+        * in order to check if the running kernel/container
+        * environment supports it.
+        */
+       per_thread_cwd_check();
 
        if (!cluster_probe_ok()) {
                exit(1);
@@ -1832,11 +1798,14 @@ extern void build_options(bool screen);
                exit(1);
        }
 
-       if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC
-           && !lp_parm_bool(-1, "server role check", "inhibit", false)) {
-               DEBUG(0, ("server role = 'active directory domain controller' not compatible with running smbd standalone. \n"));
-               DEBUGADD(0, ("You should start 'samba' instead, and it will control starting smbd if required\n"));
-               exit(1);
+       if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
+               if (!lp_parm_bool(-1, "server role check", "inhibit", false)) {
+                       DBG_ERR("server role = 'active directory domain controller' not compatible with running smbd standalone. \n");
+                       DEBUGADD(0, ("You should start 'samba' instead, and it will control starting smbd if required\n"));
+                       exit(1);
+               }
+               /* Main 'samba' daemon will notify */
+               daemon_sd_notifications(false);
        }
 
        /* ...NOTE... Log files are working from this point! */
@@ -1858,23 +1827,27 @@ extern void build_options(bool screen);
        main_server_id = messaging_server_id(msg_ctx);
        set_profile_level(profiling_level, &main_server_id);
 
-       if (!is_daemon && !is_a_socket(0)) {
-               if (!interactive) {
+       if (!cmdline_daemon_cfg->daemon && !is_a_socket(0)) {
+               if (!cmdline_daemon_cfg->interactive) {
                        DEBUG(3, ("Standard input is not a socket, "
                                  "assuming -D option\n"));
                }
 
                /*
-                * Setting is_daemon here prevents us from eventually calling
+                * Setting "daemon" here prevents us from eventually calling
                 * the open_sockets_inetd()
                 */
 
-               is_daemon = True;
+               cmdline_daemon_cfg->daemon = true;
        }
 
-       if (is_daemon && !interactive) {
+       if (cmdline_daemon_cfg->daemon && !cmdline_daemon_cfg->interactive) {
                DEBUG(3, ("Becoming a daemon.\n"));
-               become_daemon(Fork, no_process_group, log_stdout);
+               become_daemon(cmdline_daemon_cfg->fork,
+                             cmdline_daemon_cfg->no_process_group,
+                             log_stdout);
+       } else {
+               daemon_status("smbd", "Starting process ...");
        }
 
 #ifdef HAVE_SETPGID
@@ -1882,8 +1855,11 @@ extern void build_options(bool screen);
         * If we're interactive we want to set our own process group for
         * signal management.
         */
-       if (interactive && !no_process_group)
+       if (cmdline_daemon_cfg->interactive &&
+           !cmdline_daemon_cfg->no_process_group)
+       {
                setpgid( (pid_t)0, (pid_t)0);
+       }
 #endif
 
        if (!directory_exist(lp_lock_directory()))
@@ -1892,15 +1868,15 @@ extern void build_options(bool screen);
        if (!directory_exist(lp_pid_directory()))
                mkdir(lp_pid_directory(), 0755);
 
-       if (is_daemon)
+       if (cmdline_daemon_cfg->daemon)
                pidfile_create(lp_pid_directory(), "smbd");
 
-       status = reinit_after_fork(msg_ctx, ev_ctx, false, NULL);
+       status = reinit_after_fork(msg_ctx, ev_ctx, false);
        if (!NT_STATUS_IS_OK(status)) {
                exit_daemon("reinit_after_fork() failed", map_errno_from_nt_status(status));
        }
 
-       if (!interactive) {
+       if (!cmdline_daemon_cfg->interactive) {
                /*
                 * Do not initialize the parent-child-pipe before becoming a
                 * daemon: this is used to detect a died parent in the child
@@ -1916,7 +1892,7 @@ extern void build_options(bool screen);
        if (!parent) {
                exit_server("talloc(struct smbd_parent_context) failed");
        }
-       parent->interactive = interactive;
+       parent->interactive = cmdline_daemon_cfg->interactive;
        parent->ev_ctx = ev_ctx;
        parent->msg_ctx = msg_ctx;
        am_parent = parent;
@@ -1956,7 +1932,7 @@ extern void build_options(bool screen);
                exit_daemon("smbd can not open secrets.tdb", EACCES);
        }
 
-       if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC) {
+       if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC || lp_server_role() == ROLE_IPA_DC) {
                struct loadparm_context *lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers());
                if (!open_schannel_session_store(NULL, lp_ctx)) {
                        exit_daemon("ERROR: Samba cannot open schannel store for secured NETLOGON operations.", EACCES);
@@ -1996,11 +1972,17 @@ extern void build_options(bool screen);
                exit_daemon("Samba cannot init leases", EACCES);
        }
 
-       if (!smbd_notifyd_init(msg_ctx, interactive, &parent->notifyd)) {
+       if (!smbd_notifyd_init(
+                   msg_ctx,
+                   cmdline_daemon_cfg->interactive,
+                   &parent->notifyd)) {
                exit_daemon("Samba cannot init notification", EACCES);
        }
 
-       if (!cleanupd_init(msg_ctx, interactive, &parent->cleanupd)) {
+       if (!cleanupd_init(
+                   msg_ctx,
+                   cmdline_daemon_cfg->interactive,
+                   &parent->cleanupd)) {
                exit_daemon("Samba cannot init the cleanupd", EACCES);
        }
 
@@ -2019,7 +2001,8 @@ extern void build_options(bool screen);
           after the fork on every single connection.  This is a small
           performance improvment and reduces the total number of system
           fds used. */
-       if (!share_info_db_init()) {
+       status = share_info_db_init();
+       if (!NT_STATUS_IS_OK(status)) {
                exit_daemon("ERROR: failed to load share info db.", EACCES);
        }
 
@@ -2047,7 +2030,7 @@ extern void build_options(bool screen);
        if (lp_clustering() && !lp_allow_unsafe_cluster_upgrade()) {
                status = smbd_claim_version(msg_ctx, samba_version_string());
                if (!NT_STATUS_IS_OK(status)) {
-                       DBG_WARNING("Could not claim version: %s\n",
+                       DBG_ERR("Could not claim version: %s\n",
                                    nt_errstr(status));
                        return -1;
                }
@@ -2074,57 +2057,12 @@ extern void build_options(bool screen);
                return -1;
        }
 
-       if (is_daemon && !interactive) {
-               if (rpc_epmapper_daemon() == RPC_DAEMON_FORK) {
-                       start_epmd(ev_ctx, msg_ctx);
-               }
-       }
-
-       if (!dcesrv_ep_setup(ev_ctx, msg_ctx)) {
-               exit_daemon("Samba cannot setup ep pipe", EACCES);
-       }
-
-       if (is_daemon && !interactive) {
+       if (!cmdline_daemon_cfg->interactive) {
                daemon_ready("smbd");
        }
 
-       /* only start other daemons if we are running as a daemon
-        * -- bad things will happen if smbd is launched via inetd
-        *  and we fork a copy of ourselves here */
-       if (is_daemon && !interactive) {
-
-               if (rpc_lsasd_daemon() == RPC_DAEMON_FORK) {
-                       start_lsasd(ev_ctx, msg_ctx);
-               }
-
-               if (rpc_fss_daemon() == RPC_DAEMON_FORK) {
-                       start_fssd(ev_ctx, msg_ctx);
-               }
-
-               if (!lp__disable_spoolss() &&
-                   (rpc_spoolss_daemon() != RPC_DAEMON_DISABLED)) {
-                       bool bgq = lp_parm_bool(-1, "smbd", "backgroundqueue", true);
-
-                       if (!printing_subsystem_init(ev_ctx, msg_ctx, true, bgq)) {
-                               exit_daemon("Samba failed to init printing subsystem", EACCES);
-                       }
-               }
-
-#ifdef WITH_SPOTLIGHT
-               if ((rpc_mdssvc_mode() == RPC_SERVICE_MODE_EXTERNAL) &&
-                   (rpc_mdssd_daemon() == RPC_DAEMON_FORK)) {
-                       start_mdssd(ev_ctx, msg_ctx);
-               }
-#endif
-       } else if (!lp__disable_spoolss() &&
-                  (rpc_spoolss_daemon() != RPC_DAEMON_DISABLED)) {
-               if (!printing_subsystem_init(ev_ctx, msg_ctx, false, false)) {
-                       exit(1);
-               }
-       }
-
-       if (!is_daemon) {
-               int sock;
+       if (!cmdline_daemon_cfg->daemon) {
+               int ret, sock;
 
                /* inetd mode */
                TALLOC_FREE(frame);
@@ -2135,7 +2073,19 @@ extern void build_options(bool screen);
                sock = dup(0);
 
                /* close stdin, stdout (if not logging to it), but not stderr */
-               close_low_fds(true, !debug_get_output_is_stdout(), false);
+               ret = close_low_fd(0);
+               if (ret != 0) {
+                       DBG_ERR("close_low_fd(0) failed: %s\n", strerror(ret));
+                       return 1;
+               }
+               if (!debug_get_output_is_stdout()) {
+                       ret = close_low_fd(1);
+                       if (ret != 0) {
+                               DBG_ERR("close_low_fd(1) failed: %s\n",
+                                       strerror(ret));
+                               return 1;
+                       }
+               }
 
 #ifdef HAVE_ATEXIT
                atexit(killkids);
@@ -2153,18 +2103,11 @@ extern void build_options(bool screen);
        if (!open_sockets_smbd(parent, ev_ctx, msg_ctx, ports))
                exit_server("open_sockets_smbd() failed");
 
-       /* do a printer update now that all messaging has been set up,
-        * before we allow clients to start connecting */
-       if (!lp__disable_spoolss() &&
-           (rpc_spoolss_daemon() != RPC_DAEMON_DISABLED)) {
-               printing_subsystem_update(ev_ctx, msg_ctx, false);
-       }
-
        TALLOC_FREE(frame);
        /* make sure we always have a valid stackframe */
        frame = talloc_stackframe();
 
-       if (!Fork) {
+       if (!cmdline_daemon_cfg->fork) {
                /* if we are running in the foreground then look for
                   EOF on stdin, and exit if it happens. This allows
                   us to die if the parent process dies
@@ -2172,7 +2115,7 @@ extern void build_options(bool screen);
                */
                struct stat st;
                if (fstat(0, &st) != 0) {
-                       return false;
+                       return 1;
                }
                if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) {
                        tevent_add_fd(ev_ctx,