#include "includes.h"
#include "system/filesys.h"
+#include "lib/util/server_id.h"
#include "popt_common.h"
#include "smbd/smbd.h"
#include "smbd/globals.h"
#include "registry/reg_init_full.h"
#include "libcli/auth/schannel.h"
#include "secrets.h"
-#include "memcache.h"
+#include "../lib/util/memcache.h"
#include "ctdbd_conn.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"
#include "messages.h"
+#include "messages_ctdb.h"
#include "smbprofile.h"
#include "lib/id_cache.h"
#include "lib/param/param.h"
#include "lib/conn_tdb.h"
#include "../lib/util/pidfile.h"
#include "lib/smbd_shim.h"
+#include "scavenger.h"
+#include "locking/leases_db.h"
+#include "smbd/notifyd/notifyd.h"
+#include "smbd/smbd_cleanupd.h"
+#include "lib/util/sys_rw.h"
+#include "cleanupdb.h"
+#include "g_lock.h"
+
+#ifdef CLUSTER_SUPPORT
+#include "ctdb_protocol.h"
+#endif
struct smbd_open_socket;
struct smbd_child_pid;
struct smbd_child_pid *children;
size_t num_children;
+ struct server_id cleanupd;
+ struct server_id notifyd;
+
struct tevent_timer *cleanup_te;
};
extern void start_lsasd(struct tevent_context *ev_ctx,
struct messaging_context *msg_ctx);
-#ifdef WITH_DFS
-extern int dcelogin_atmost_once;
-#endif /* WITH_DFS */
+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.
printing_subsystem_update(ev_ctx, msg, false);
}
-/*******************************************************************
- What to do when printcap is updated.
- ********************************************************************/
-
-static void smb_pcap_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);
-
- DEBUG(10,("Got message saying pcap was updated. Reloading.\n"));
- change_to_root_user();
- delete_and_reload_printers(ev_ctx, msg);
-}
-
/*******************************************************************
Delete a statcache entry.
********************************************************************/
DATA_BLOB *data)
{
int sig;
+ struct server_id_buf tmp;
if (data->length != sizeof(sig)) {
DEBUG(0, ("Process %s sent bogus signal injection request\n",
- procid_str_static(&src)));
+ server_id_str_buf(src, &tmp)));
return;
}
#if HAVE_STRSIGNAL
DEBUG(0, ("Process %s requested injection of signal %d (%s)\n",
- procid_str_static(&src), sig, strsignal(sig)));
+ server_id_str_buf(src, &tmp), sig, strsignal(sig)));
#else
DEBUG(0, ("Process %s requested injection of signal %d\n",
- procid_str_static(&src), sig));
+ server_id_str_buf(src, &tmp), sig));
#endif
kill(getpid(), sig);
}
#endif /* DEVELOPER */
-NTSTATUS messaging_send_to_children(struct messaging_context *msg_ctx,
- uint32_t msg_type, DATA_BLOB* data)
+static NTSTATUS messaging_send_to_children(struct messaging_context *msg_ctx,
+ uint32_t msg_type, DATA_BLOB* data)
{
NTSTATUS status;
struct smbd_parent_context *parent = am_parent;
pid_to_procid(child->pid),
msg_type, data);
if (!NT_STATUS_IS_OK(status)) {
- return status;
+ DBG_DEBUG("messaging_send(%d) failed: %s\n",
+ (int)child->pid, nt_errstr(status));
}
}
return NT_STATUS_OK;
}
+static void smb_parent_send_to_children(struct messaging_context *ctx,
+ void* data,
+ uint32_t msg_type,
+ struct server_id srv_id,
+ DATA_BLOB* msg_data)
+{
+ messaging_send_to_children(ctx, msg_type, msg_data);
+}
+
/*
* Parent smbd process sets its own debug level first and then
* sends a message to all the smbd children to adjust their debug
messaging_send_to_children(ctx, msg_type, msg_data);
}
-struct smbd_parent_notify_state {
- struct tevent_context *ev;
- struct messaging_context *msg;
- uint32_t msgtype;
- struct notify_context *notify;
-};
+#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)
+{
+ struct smbd_child_pid *child;
-static int smbd_parent_notify_cleanup(void *private_data);
-static void smbd_parent_notify_cleanup_done(struct tevent_req *req);
-static void smbd_parent_notify_proxy_done(struct tevent_req *req);
+ child = talloc_zero(parent, struct smbd_child_pid);
+ if (child == NULL) {
+ DEBUG(0, ("Could not add child struct -- malloc failed\n"));
+ return;
+ }
+ child->pid = pid;
+ DLIST_ADD(parent->children, child);
+ parent->num_children += 1;
+}
+
+static void smb_tell_num_children(struct messaging_context *ctx, void *data,
+ uint32_t msg_type, struct server_id srv_id,
+ DATA_BLOB *msg_data)
+{
+ uint8_t buf[sizeof(uint32_t)];
+
+ if (am_parent) {
+ SIVAL(buf, 0, am_parent->num_children);
+ messaging_send_buf(ctx, srv_id, MSG_SMB_NUM_CHILDREN,
+ buf, sizeof(buf));
+ }
+}
+
+static void notifyd_stopped(struct tevent_req *req);
-static bool smbd_parent_notify_init(TALLOC_CTX *mem_ctx,
- struct messaging_context *msg,
- struct tevent_context *ev)
+static struct tevent_req *notifyd_req(struct messaging_context *msg_ctx,
+ struct tevent_context *ev)
{
- struct smbd_parent_notify_state *state;
struct tevent_req *req;
+ sys_notify_watch_fn sys_notify_watch = NULL;
+ struct sys_notify_context *sys_notify_ctx = NULL;
+ struct ctdbd_connection *ctdbd_conn = NULL;
- state = talloc(mem_ctx, struct smbd_parent_notify_state);
- if (state == NULL) {
- return false;
+ if (lp_kernel_change_notify()) {
+
+#ifdef HAVE_INOTIFY
+ if (lp_parm_bool(-1, "notify", "inotify", true)) {
+ sys_notify_watch = inotify_watch;
+ }
+#endif
+
+#ifdef HAVE_FAM
+ if (lp_parm_bool(-1, "notify", "fam",
+ (sys_notify_watch == NULL))) {
+ sys_notify_watch = fam_watch;
+ }
+#endif
}
- state->msg = msg;
- state->ev = ev;
- state->msgtype = MSG_SMB_NOTIFY_CLEANUP;
- state->notify = notify_init(state, msg, ev);
- if (state->notify == NULL) {
- goto fail;
+ if (sys_notify_watch != NULL) {
+ sys_notify_ctx = sys_notify_context_create(msg_ctx, ev);
+ if (sys_notify_ctx == NULL) {
+ return NULL;
+ }
}
- req = background_job_send(
- state, state->ev, state->msg, &state->msgtype, 1,
- lp_parm_int(-1, "smbd", "notify cleanup interval", 60),
- smbd_parent_notify_cleanup, state->notify);
+
+ if (lp_clustering()) {
+ ctdbd_conn = messaging_ctdb_connection();
+ }
+
+ req = notifyd_send(msg_ctx, ev, msg_ctx, ctdbd_conn,
+ sys_notify_watch, sys_notify_ctx);
if (req == NULL) {
- goto fail;
+ TALLOC_FREE(sys_notify_ctx);
+ return NULL;
+ }
+ tevent_req_set_callback(req, notifyd_stopped, msg_ctx);
+
+ return req;
+}
+
+static void notifyd_stopped(struct tevent_req *req)
+{
+ int ret;
+
+ ret = notifyd_recv(req);
+ TALLOC_FREE(req);
+ DEBUG(1, ("notifyd stopped: %s\n", strerror(ret)));
+}
+
+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;
+ pid_t pid;
+ NTSTATUS status;
+ bool ok;
+
+ if (interactive) {
+ req = notifyd_req(msg, ev);
+ return (req != NULL);
+ }
+
+ pid = fork();
+ if (pid == -1) {
+ DEBUG(1, ("%s: fork failed: %s\n", __func__,
+ strerror(errno)));
+ return false;
}
- tevent_req_set_callback(req, smbd_parent_notify_cleanup_done, state);
- if (!lp_clustering()) {
+ if (pid != 0) {
+ if (am_parent != 0) {
+ add_child_pid(am_parent, pid);
+ }
+ *ppid = pid_to_procid(pid);
return true;
}
- req = notify_cluster_proxy_send(state, ev, state->notify);
+ status = smbd_reinit_after_fork(msg, ev, true, "smbd-notifyd");
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("%s: reinit_after_fork failed: %s\n",
+ __func__, nt_errstr(status)));
+ exit(1);
+ }
+
+ req = notifyd_req(msg, ev);
if (req == NULL) {
- goto fail;
+ exit(1);
}
- tevent_req_set_callback(req, smbd_parent_notify_proxy_done, state);
+ tevent_req_set_callback(req, notifyd_stopped, msg);
- return true;
-fail:
- TALLOC_FREE(state);
- return false;
+ /* 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,
+ NULL);
+
+ ok = tevent_req_poll(req, ev);
+ if (!ok) {
+ DBG_WARNING("tevent_req_poll returned %s\n", strerror(errno));
+ exit(1);
+ }
+ exit(0);
}
-static int smbd_parent_notify_cleanup(void *private_data)
+static void notifyd_init_trigger(struct tevent_req *req);
+
+struct notifyd_init_state {
+ bool ok;
+ struct tevent_context *ev;
+ struct messaging_context *msg;
+ struct server_id *ppid;
+};
+
+static struct tevent_req *notifyd_init_send(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct messaging_context *msg,
+ struct server_id *ppid)
{
- struct notify_context *notify = talloc_get_type_abort(
- private_data, struct notify_context);
- notify_cleanup(notify);
- return lp_parm_int(-1, "smbd", "notify cleanup interval", 60);
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct notifyd_init_state *state = NULL;
+
+ req = tevent_req_create(mem_ctx, &state, struct notifyd_init_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ *state = (struct notifyd_init_state) {
+ .msg = msg,
+ .ev = ev,
+ .ppid = ppid
+ };
+
+ subreq = tevent_wakeup_send(state, ev, tevent_timeval_current_ofs(1, 0));
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq, notifyd_init_trigger, req);
+ return req;
}
-static void smbd_parent_notify_cleanup_done(struct tevent_req *req)
+static void notifyd_init_trigger(struct tevent_req *subreq)
{
- struct smbd_parent_notify_state *state = tevent_req_callback_data(
- req, struct smbd_parent_notify_state);
- NTSTATUS status;
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct notifyd_init_state *state = tevent_req_data(
+ req, struct notifyd_init_state);
+ bool ok;
+
+ DBG_NOTICE("Triggering notifyd startup\n");
+
+ ok = tevent_wakeup_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!ok) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
- status = background_job_recv(req);
- TALLOC_FREE(req);
- DEBUG(1, ("notify cleanup job ended with %s\n", nt_errstr(status)));
+ state->ok = smbd_notifyd_init(state->msg, false, state->ppid);
+ if (state->ok) {
+ DBG_WARNING("notifyd restarted\n");
+ tevent_req_done(req);
+ return;
+ }
- /*
- * Provide self-healing: Whatever the error condition was, it
- * will have printed it into log.smbd. Just retrying and
- * spamming log.smbd once a minute should be fine.
- */
- req = background_job_send(
- state, state->ev, state->msg, &state->msgtype, 1, 60,
- smbd_parent_notify_cleanup, state->notify);
- if (req == NULL) {
- DEBUG(1, ("background_job_send failed\n"));
+ DBG_NOTICE("notifyd startup failed, rescheduling\n");
+
+ subreq = tevent_wakeup_send(state, state->ev,
+ tevent_timeval_current_ofs(1, 0));
+ if (tevent_req_nomem(subreq, req)) {
+ DBG_ERR("scheduling notifyd restart failed, giving up\n");
return;
}
- tevent_req_set_callback(req, smbd_parent_notify_cleanup_done, state);
+
+ tevent_req_set_callback(subreq, notifyd_init_trigger, req);
+ return;
}
-static void smbd_parent_notify_proxy_done(struct tevent_req *req)
+static bool notifyd_init_recv(struct tevent_req *req)
{
- int ret;
+ struct notifyd_init_state *state = tevent_req_data(
+ req, struct notifyd_init_state);
+
+ return state->ok;
+}
- ret = notify_cluster_proxy_recv(req);
+static void notifyd_started(struct tevent_req *req)
+{
+ bool ok;
+
+ ok = notifyd_init_recv(req);
TALLOC_FREE(req);
- DEBUG(1, ("notify proxy job ended with %s\n", strerror(ret)));
+ if (!ok) {
+ DBG_ERR("Failed to restart notifyd, giving up\n");
+ return;
+ }
}
-static void smb_parent_force_tdis(struct messaging_context *ctx,
- void* data,
- uint32_t msg_type,
- struct server_id srv_id,
- DATA_BLOB* msg_data)
+static void cleanupd_stopped(struct tevent_req *req);
+
+static bool cleanupd_init(struct messaging_context *msg, bool interactive,
+ struct server_id *ppid)
{
- messaging_send_to_children(ctx, msg_type, msg_data);
+ struct tevent_context *ev = messaging_tevent_context(msg);
+ struct server_id parent_id = messaging_server_id(msg);
+ struct tevent_req *req;
+ pid_t pid;
+ NTSTATUS status;
+ ssize_t rwret;
+ int ret;
+ bool ok;
+ char c;
+ int up_pipe[2];
+
+ if (interactive) {
+ req = smbd_cleanupd_send(msg, ev, msg, parent_id.pid);
+ *ppid = messaging_server_id(msg);
+ return (req != NULL);
+ }
+
+ ret = pipe(up_pipe);
+ if (ret == -1) {
+ DBG_WARNING("pipe failed: %s\n", strerror(errno));
+ return false;
+ }
+
+ pid = fork();
+ if (pid == -1) {
+ DBG_WARNING("fork failed: %s\n", strerror(errno));
+ close(up_pipe[0]);
+ close(up_pipe[1]);
+ return false;
+ }
+
+ if (pid != 0) {
+
+ close(up_pipe[1]);
+ rwret = sys_read(up_pipe[0], &c, 1);
+ close(up_pipe[0]);
+
+ if (rwret == -1) {
+ DBG_WARNING("sys_read failed: %s\n", strerror(errno));
+ return false;
+ }
+ if (rwret == 0) {
+ DBG_WARNING("cleanupd could not start\n");
+ return false;
+ }
+ if (c != 0) {
+ DBG_WARNING("cleanupd returned %d\n", (int)c);
+ return false;
+ }
+
+ DBG_DEBUG("Started cleanupd pid=%d\n", (int)pid);
+
+ if (am_parent != NULL) {
+ add_child_pid(am_parent, pid);
+ }
+
+ *ppid = pid_to_procid(pid);
+ return true;
+ }
+
+ close(up_pipe[0]);
+
+ status = smbd_reinit_after_fork(msg, ev, true, "cleanupd");
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("reinit_after_fork failed: %s\n",
+ nt_errstr(status));
+ c = 1;
+ sys_write(up_pipe[1], &c, 1);
+
+ exit(1);
+ }
+
+ req = smbd_cleanupd_send(msg, ev, msg, parent_id.pid);
+ if (req == NULL) {
+ DBG_WARNING("smbd_cleanupd_send failed\n");
+ c = 2;
+ sys_write(up_pipe[1], &c, 1);
+
+ exit(1);
+ }
+
+ tevent_req_set_callback(req, cleanupd_stopped, msg);
+
+ c = 0;
+ rwret = sys_write(up_pipe[1], &c, 1);
+ close(up_pipe[1]);
+
+ if (rwret == -1) {
+ DBG_WARNING("sys_write failed: %s\n", strerror(errno));
+ exit(1);
+ }
+ if (rwret != 1) {
+ DBG_WARNING("sys_write could not write result\n");
+ exit(1);
+ }
+
+ ok = tevent_req_poll(req, ev);
+ if (!ok) {
+ DBG_WARNING("tevent_req_poll returned %s\n", strerror(errno));
+ }
+ exit(0);
}
-static void add_child_pid(struct smbd_parent_context *parent,
- pid_t pid)
+static void cleanupd_stopped(struct tevent_req *req)
{
- struct smbd_child_pid *child;
+ NTSTATUS status;
- child = talloc_zero(parent, struct smbd_child_pid);
- if (child == NULL) {
- DEBUG(0, ("Could not add child struct -- malloc failed\n"));
+ status = smbd_cleanupd_recv(req);
+ DBG_WARNING("cleanupd stopped: %s\n", nt_errstr(status));
+}
+
+static void cleanupd_init_trigger(struct tevent_req *req);
+
+struct cleanup_init_state {
+ bool ok;
+ struct tevent_context *ev;
+ struct messaging_context *msg;
+ struct server_id *ppid;
+};
+
+static struct tevent_req *cleanupd_init_send(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct messaging_context *msg,
+ struct server_id *ppid)
+{
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct cleanup_init_state *state = NULL;
+
+ req = tevent_req_create(mem_ctx, &state, struct cleanup_init_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ *state = (struct cleanup_init_state) {
+ .msg = msg,
+ .ev = ev,
+ .ppid = ppid
+ };
+
+ subreq = tevent_wakeup_send(state, ev, tevent_timeval_current_ofs(0, 0));
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq, cleanupd_init_trigger, req);
+ return req;
+}
+
+static void cleanupd_init_trigger(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cleanup_init_state *state = tevent_req_data(
+ req, struct cleanup_init_state);
+ bool ok;
+
+ DBG_NOTICE("Triggering cleanupd startup\n");
+
+ ok = tevent_wakeup_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!ok) {
+ tevent_req_error(req, ENOMEM);
return;
}
- child->pid = pid;
- DLIST_ADD(parent->children, child);
- parent->num_children += 1;
+
+ state->ok = cleanupd_init(state->msg, false, state->ppid);
+ if (state->ok) {
+ DBG_WARNING("cleanupd restarted\n");
+ tevent_req_done(req);
+ return;
+ }
+
+ DBG_NOTICE("cleanupd startup failed, rescheduling\n");
+
+ subreq = tevent_wakeup_send(state, state->ev,
+ tevent_timeval_current_ofs(1, 0));
+ if (tevent_req_nomem(subreq, req)) {
+ DBG_ERR("scheduling cleanupd restart failed, giving up\n");
+ return;
+ }
+
+ tevent_req_set_callback(subreq, cleanupd_init_trigger, req);
+ return;
+}
+
+static bool cleanupd_init_recv(struct tevent_req *req)
+{
+ struct cleanup_init_state *state = tevent_req_data(
+ req, struct cleanup_init_state);
+
+ return state->ok;
}
/*
parent->cleanup_te = NULL;
- DEBUG(1,("Cleaning up brl and lock database after unclean shutdown\n"));
- message_send_all(parent->msg_ctx, MSG_SMB_UNLOCK, NULL, 0, NULL);
- messaging_send_buf(parent->msg_ctx,
- messaging_server_id(parent->msg_ctx),
- MSG_SMB_BRL_VALIDATE, NULL, 0);
+ messaging_send_buf(parent->msg_ctx, parent->cleanupd,
+ MSG_SMB_UNLOCK, NULL, 0);
+}
+
+static void cleanupd_started(struct tevent_req *req)
+{
+ bool ok;
+ NTSTATUS status;
+ struct smbd_parent_context *parent = tevent_req_callback_data(
+ req, struct smbd_parent_context);
+
+ ok = cleanupd_init_recv(req);
+ TALLOC_FREE(req);
+ if (!ok) {
+ DBG_ERR("Failed to restart cleanupd, giving up\n");
+ return;
+ }
+
+ status = messaging_send(parent->msg_ctx,
+ parent->cleanupd,
+ MSG_SMB_NOTIFY_CLEANUP,
+ &data_blob_null);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("messaging_send returned %s\n",
+ nt_errstr(status));
+ }
}
static void remove_child_pid(struct smbd_parent_context *parent,
bool unclean_shutdown)
{
struct smbd_child_pid *child;
- struct server_id child_id;
-
- child_id = pid_to_procid(pid);
+ NTSTATUS status;
+ bool ok;
for (child = parent->children; child != NULL; child = child->next) {
if (child->pid == pid) {
return;
}
+ if (pid == procid_to_pid(&parent->cleanupd)) {
+ struct tevent_req *req;
+
+ server_id_set_disconnected(&parent->cleanupd);
+
+ DBG_WARNING("Restarting cleanupd\n");
+ req = cleanupd_init_send(messaging_tevent_context(parent->msg_ctx),
+ parent,
+ parent->msg_ctx,
+ &parent->cleanupd);
+ if (req == NULL) {
+ DBG_ERR("Failed to restart cleanupd\n");
+ return;
+ }
+ tevent_req_set_callback(req, cleanupd_started, parent);
+ return;
+ }
+
+ if (pid == procid_to_pid(&parent->notifyd)) {
+ struct tevent_req *req;
+ struct tevent_context *ev = messaging_tevent_context(
+ parent->msg_ctx);
+
+ server_id_set_disconnected(&parent->notifyd);
+
+ DBG_WARNING("Restarting notifyd\n");
+ req = notifyd_init_send(ev,
+ parent,
+ parent->msg_ctx,
+ &parent->notifyd);
+ if (req == NULL) {
+ DBG_ERR("Failed to restart notifyd\n");
+ return;
+ }
+ tevent_req_set_callback(req, notifyd_started, parent);
+ return;
+ }
+
+ ok = cleanupdb_store_child(pid, unclean_shutdown);
+ if (!ok) {
+ DBG_ERR("cleanupdb_store_child failed\n");
+ return;
+ }
+
+ if (!server_id_is_disconnected(&parent->cleanupd)) {
+ status = messaging_send(parent->msg_ctx,
+ parent->cleanupd,
+ MSG_SMB_NOTIFY_CLEANUP,
+ &data_blob_null);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("messaging_send returned %s\n",
+ nt_errstr(status));
+ }
+ }
+
if (unclean_shutdown) {
/* a child terminated uncleanly so tickle all
processes to see if they can grab any of the
DEBUG(1,("Scheduled cleanup of brl and lock database after unclean shutdown\n"));
}
}
-
- if (!serverid_deregister(child_id)) {
- DEBUG(1, ("Could not remove pid %d from serverid.tdb\n",
- (int)pid));
- }
}
/****************************************************************************
talloc_get_type_abort(private_data,
struct smbd_parent_context);
- while ((pid = sys_waitpid(-1, &status, WNOHANG)) > 0) {
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
bool unclean_shutdown = False;
/* If the child terminated normally, assume
socklen_t in_addrlen = sizeof(addr);
int fd;
pid_t pid = 0;
- uint64_t unique_id;
fd = accept(s->fd, (struct sockaddr *)(void *)&addr,&in_addrlen);
if (fd == -1 && errno == EINTR)
}
if (s->parent->interactive) {
- reinit_after_fork(msg_ctx, ev, true);
+ reinit_after_fork(msg_ctx, ev, true, NULL);
smbd_process(ev, msg_ctx, fd, true);
exit_server_cleanly("end of interactive mode");
return;
return;
}
- /*
- * Generate a unique id in the parent process so that we use
- * the global random state in the parent.
- */
- unique_id = serverid_get_random_unique_id();
-
pid = fork();
if (pid == 0) {
NTSTATUS status = NT_STATUS_OK;
- /* Child code ... */
- am_parent = NULL;
-
/*
* Can't use TALLOC_FREE here. Nulling out the argument to it
* would overwrite memory we've just freed.
talloc_free(s->parent);
s = NULL;
- set_my_unique_id(unique_id);
-
/* Stop zombies, the parent explicitly handles
* them, counting worker smbds. */
CatchChild();
- status = reinit_after_fork(msg_ctx,
- ev,
- true);
+ status = smbd_reinit_after_fork(msg_ctx, ev, true, NULL);
if (!NT_STATUS_IS_OK(status)) {
if (NT_STATUS_EQUAL(status,
NT_STATUS_TOO_MANY_OPENED_FILES)) {
goto exit;
}
if (lp_clustering() &&
- NT_STATUS_EQUAL(status,
- NT_STATUS_INTERNAL_DB_ERROR)) {
- DEBUG(1,("child process cannot initialize "
- "because connection to CTDB "
- "has failed\n"));
+ (NT_STATUS_EQUAL(
+ status, NT_STATUS_INTERNAL_DB_ERROR) ||
+ NT_STATUS_EQUAL(
+ status, NT_STATUS_CONNECTION_REFUSED))) {
+ DEBUG(1, ("child process cannot initialize "
+ "because connection to CTDB "
+ "has failed: %s\n",
+ nt_errstr(status)));
goto exit;
}
ifss,
true);
if (s->fd == -1) {
- DEBUG(0,("smbd_open_once_socket: open_socket_in: "
+ DEBUG(0,("smbd_open_one_socket: open_socket_in: "
"%s\n", strerror(errno)));
TALLOC_FREE(s);
/*
set_blocking(s->fd, False);
if (listen(s->fd, SMBD_LISTEN_BACKLOG) == -1) {
- DEBUG(0,("open_sockets_smbd: listen: "
+ DEBUG(0,("smbd_open_one_socket: listen: "
"%s\n", strerror(errno)));
close(s->fd);
TALLOC_FREE(s);
smbd_accept_connection,
s);
if (!s->fde) {
- DEBUG(0,("open_sockets_smbd: "
+ DEBUG(0,("smbd_open_one_socket: "
"tevent_add_fd: %s\n",
strerror(errno)));
close(s->fd);
}
tevent_fd_set_close_fn(s->fde, smbd_open_socket_close_fn);
- DLIST_ADD_END(parent->sockets, s, struct smbd_open_socket *);
+ DLIST_ADD_END(parent->sockets, s);
return true;
}
/* use a reasonable default set of ports - listing on 445 and 139 */
if (smb_ports) {
- ports = (const char **)str_list_make_v3(talloc_tos(), smb_ports, NULL);
+ char **l;
+ l = str_list_make_v3(talloc_tos(), smb_ports, NULL);
+ ports = discard_const_p(const char *, l);
}
for (j = 0; ports && ports[j]; j++) {
continue;
}
- if (!smbd_open_one_socket(parent,
- ev_ctx,
- &ss,
- port)) {
- return false;
- }
+ /*
+ * If we fail to open any sockets
+ * in this loop the parent-sockets == NULL
+ * case below will prevent us from starting.
+ */
+
+ (void)smbd_open_one_socket(parent,
+ ev_ctx,
+ &ss,
+ port);
}
}
}
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, ev_ctx, MSG_PRINTER_PCAP,
- smb_pcap_updated);
- messaging_register(msg_ctx, NULL, MSG_SMB_BRL_VALIDATE,
- brl_revalidate);
messaging_register(msg_ctx, NULL, MSG_SMB_FORCE_TDIS,
- smb_parent_force_tdis);
+ 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,
+ smb_tell_num_children);
messaging_register(msg_ctx, NULL,
ID_CACHE_DELETE, smbd_parent_id_cache_delete);
messaging_register(msg_ctx, NULL,
ID_CACHE_KILL, smbd_parent_id_cache_kill);
+ messaging_register(msg_ctx, NULL, MSG_SMB_NOTIFY_STARTED,
+ smb_parent_send_to_children);
#ifdef CLUSTER_SUPPORT
if (lp_clustering()) {
- ctdbd_register_reconfigure(messaging_ctdbd_connection());
+ 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
}
}
+struct smbd_parent_tevent_trace_state {
+ TALLOC_CTX *frame;
+};
+
+static void smbd_parent_tevent_trace_callback(enum tevent_trace_point point,
+ void *private_data)
+{
+ struct smbd_parent_tevent_trace_state *state =
+ (struct smbd_parent_tevent_trace_state *)private_data;
+
+ switch (point) {
+ case TEVENT_TRACE_BEFORE_WAIT:
+ break;
+ case TEVENT_TRACE_AFTER_WAIT:
+ break;
+ case TEVENT_TRACE_BEFORE_LOOP_ONCE:
+ TALLOC_FREE(state->frame);
+ state->frame = talloc_stackframe();
+ break;
+ case TEVENT_TRACE_AFTER_LOOP_ONCE:
+ TALLOC_FREE(state->frame);
+ break;
+ }
+
+ errno = 0;
+}
+
static void smbd_parent_loop(struct tevent_context *ev_ctx,
struct smbd_parent_context *parent)
{
+ struct smbd_parent_tevent_trace_state trace_state = {
+ .frame = NULL,
+ };
+ int ret = 0;
+
+ tevent_set_trace_callback(ev_ctx, smbd_parent_tevent_trace_callback,
+ &trace_state);
+
/* now accept incoming connections - forking a new process
for each incoming connection */
DEBUG(2,("waiting for connections\n"));
- while (1) {
- int ret;
- TALLOC_CTX *frame = talloc_stackframe();
- ret = tevent_loop_once(ev_ctx);
- if (ret != 0) {
- exit_server_cleanly("tevent_loop_once() error");
- }
+ ret = tevent_loop_wait(ev_ctx);
+ if (ret != 0) {
+ DEBUG(0, ("tevent_loop_wait failed: %d, %s, exiting\n",
+ ret, strerror(errno)));
+ }
- TALLOC_FREE(frame);
- } /* end while 1 */
+ TALLOC_FREE(trace_state.frame);
/* NOTREACHED return True; */
}
printing_subsystem_update(parent->ev_ctx, parent->msg_ctx, true);
}
+struct smbd_claim_version_state {
+ TALLOC_CTX *mem_ctx;
+ char *version;
+};
+
+static void smbd_claim_version_parser(const struct g_lock_rec *locks,
+ size_t num_locks,
+ const uint8_t *data,
+ size_t datalen,
+ void *private_data)
+{
+ struct smbd_claim_version_state *state = private_data;
+
+ if (datalen == 0) {
+ state->version = NULL;
+ return;
+ }
+ if (data[datalen-1] != '\0') {
+ DBG_WARNING("Invalid samba version\n");
+ dump_data(DBGLVL_WARNING, data, datalen);
+ state->version = NULL;
+ return;
+ }
+ state->version = talloc_strdup(state->mem_ctx, (const char *)data);
+}
+
+static NTSTATUS smbd_claim_version(struct messaging_context *msg,
+ const char *version)
+{
+ const char *name = "samba_version_string";
+ struct smbd_claim_version_state state;
+ struct g_lock_ctx *ctx;
+ NTSTATUS status;
+
+ ctx = g_lock_ctx_init(msg, msg);
+ if (ctx == NULL) {
+ DBG_WARNING("g_lock_ctx_init failed\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ status = g_lock_lock(ctx, name, G_LOCK_READ,
+ (struct timeval) { .tv_sec = 60 });
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("g_lock_lock(G_LOCK_READ) failed: %s\n",
+ nt_errstr(status));
+ TALLOC_FREE(ctx);
+ return status;
+ }
+
+ state = (struct smbd_claim_version_state) { .mem_ctx = ctx };
+
+ status = g_lock_dump(ctx, name, 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, name);
+ TALLOC_FREE(ctx);
+ return status;
+ }
+
+ if ((state.version != NULL) && (strcmp(version, state.version) == 0)) {
+ /*
+ * Leave the read lock for us around. Someone else already
+ * set the version correctly
+ */
+ TALLOC_FREE(ctx);
+ return NT_STATUS_OK;
+ }
+
+ status = g_lock_lock(ctx, name, G_LOCK_WRITE,
+ (struct timeval) { .tv_sec = 60 });
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("g_lock_lock(G_LOCK_WRITE) failed: %s\n",
+ nt_errstr(status));
+ DBG_ERR("smbd %s already running, refusing to start "
+ "version %s\n", state.version, version);
+ TALLOC_FREE(ctx);
+ return NT_STATUS_SXS_VERSION_CONFLICT;
+ }
+
+ status = g_lock_write_data(ctx, name, (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));
+ TALLOC_FREE(ctx);
+ return status;
+ }
+
+ status = g_lock_lock(ctx, name, G_LOCK_READ,
+ (struct timeval) { .tv_sec = 60 });
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("g_lock_lock(G_LOCK_READ) failed: %s\n",
+ nt_errstr(status));
+ TALLOC_FREE(ctx);
+ return status;
+ }
+
+ /*
+ * Leave "ctx" dangling so that g_lock.tdb keeps opened.
+ */
+ return NT_STATUS_OK;
+}
+
/****************************************************************************
main program.
****************************************************************************/
int opt;
poptContext pc;
bool print_build_options = False;
+ struct server_id main_server_id = {0};
enum {
OPT_DAEMON = 1000,
OPT_INTERACTIVE,
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)"},
+ {"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" },
{"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_COMMON_DYNCONFIG
POPT_TABLEEND
};
struct smbd_parent_context *parent = NULL;
struct messaging_context *msg_ctx;
struct server_id server_id;
struct tevent_signal *se;
+ int profiling_level;
char *np_dir = NULL;
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,
.contend_level2_oplocks_begin = smbd_contend_level2_oplocks_begin,
.contend_level2_oplocks_end = smbd_contend_level2_oplocks_end,
setup_logging(argv[0], DEBUG_DEFAULT_STDOUT);
- load_case_tables();
+ smb_init_locale();
set_smbd_shim(&smbd_shim_fns);
exit(1);
}
- /* we want to re-seed early to prevent time delays causing
- client problems at a later date. (tridge) */
+ /*
+ * We want to die early if we can't open /dev/urandom
+ */
generate_random_buffer(NULL, 0);
/* get initial effective uid and gid */
/* Output the build options to the debug log */
build_options(False);
- if (sizeof(uint16) < 2 || sizeof(uint32) < 4) {
+ if (sizeof(uint16_t) < 2 || sizeof(uint32_t) < 4) {
DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n"));
exit(1);
}
exit(1);
}
+ if (!cluster_probe_ok()) {
+ exit(1);
+ }
+
/* Init the security context and global current_user */
init_sec_ctx();
* Initialize the event context. The event context needs to be
* initialized before the messaging context, cause the messaging
* context holds an event context.
- * FIXME: This should be s3_tevent_context_init()
*/
ev_ctx = server_event_context();
if (ev_ctx == NULL) {
init_structs();
-#ifdef WITH_PROFILE
if (!profile_setup(msg_ctx, False)) {
DEBUG(0,("ERROR: failed to setup profiling\n"));
return -1;
}
- if (profile_level != NULL) {
- int pl = atoi(profile_level);
- struct server_id src;
- DEBUG(1, ("setting profiling level: %s\n",profile_level));
- src.pid = getpid();
- set_profile_level(pl, src);
+ if (profile_level != NULL) {
+ profiling_level = atoi(profile_level);
+ } else {
+ profiling_level = lp_smbd_profiling_level();
}
-#endif
+ 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)
- DEBUG(0,("standard input is not a socket, assuming -D option\n"));
+ if (!interactive) {
+ DEBUG(3, ("Standard input is not a socket, "
+ "assuming -D option\n"));
+ }
/*
* Setting is_daemon here prevents us from eventually calling
}
if (is_daemon && !interactive) {
- DEBUG( 3, ( "Becoming a daemon.\n" ) );
+ DEBUG(3, ("Becoming a daemon.\n"));
become_daemon(Fork, no_process_group, log_stdout);
}
- set_my_unique_id(serverid_get_random_unique_id());
-
#if HAVE_SETPGID
/*
* If we're interactive we want to set our own process group for
setpgid( (pid_t)0, (pid_t)0);
#endif
- if (!directory_exist(lp_lockdir()))
- mkdir(lp_lockdir(), 0755);
+ if (!directory_exist(lp_lock_directory()))
+ mkdir(lp_lock_directory(), 0755);
- if (!directory_exist(lp_piddir()))
- mkdir(lp_piddir(), 0755);
+ if (!directory_exist(lp_pid_directory()))
+ mkdir(lp_pid_directory(), 0755);
if (is_daemon)
- pidfile_create(lp_piddir(), "smbd");
+ pidfile_create(lp_pid_directory(), "smbd");
- status = reinit_after_fork(msg_ctx,
- ev_ctx,
- false);
+ status = reinit_after_fork(msg_ctx, ev_ctx, false, NULL);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0,("reinit_after_fork() failed\n"));
- exit(1);
+ exit_daemon("reinit_after_fork() failed", map_errno_from_nt_status(status));
}
if (!interactive) {
*/
status = init_before_fork();
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("init_before_fork failed: %s\n", nt_errstr(status)));
- exit(1);
+ exit_daemon(nt_errstr(status), map_errno_from_nt_status(status));
}
}
/* Setup all the TDB's - including CLEAR_IF_FIRST tdb's. */
if (smbd_memcache() == NULL) {
- exit(1);
+ exit_daemon("no memcache available", EACCES);
}
memcache_set_global(smbd_memcache());
exit(1);
if (!secrets_init()) {
- DEBUG(0, ("ERROR: smbd can not open secrets.tdb\n"));
- exit(1);
+ exit_daemon("smbd can not open secrets.tdb", EACCES);
}
if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC) {
struct loadparm_context *lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers());
if (!open_schannel_session_store(NULL, lp_ctx)) {
- DEBUG(0,("ERROR: Samba cannot open schannel store for secured NETLOGON operations.\n"));
- exit(1);
+ exit_daemon("ERROR: Samba cannot open schannel store for secured NETLOGON operations.", EACCES);
}
TALLOC_FREE(lp_ctx);
}
if(!get_global_sam_sid()) {
- DEBUG(0,("ERROR: Samba cannot create a SAM SID.\n"));
- exit(1);
+ exit_daemon("Samba cannot create a SAM SID", EACCES);
}
server_id = messaging_server_id(msg_ctx);
status = smbXsrv_version_global_init(&server_id);
if (!NT_STATUS_IS_OK(status)) {
- exit(1);
+ exit_daemon("Samba cannot init server context", EACCES);
}
- status = smbXsrv_session_global_init();
+ status = smbXsrv_session_global_init(msg_ctx);
if (!NT_STATUS_IS_OK(status)) {
- exit(1);
+ exit_daemon("Samba cannot init session context", EACCES);
}
status = smbXsrv_tcon_global_init();
if (!NT_STATUS_IS_OK(status)) {
- exit(1);
+ exit_daemon("Samba cannot init tcon context", EACCES);
}
if (!locking_init())
- exit(1);
+ exit_daemon("Samba cannot init locking", EACCES);
- if (!messaging_tdb_parent_init(ev_ctx)) {
- exit(1);
+ if (!leases_db_init(false)) {
+ exit_daemon("Samba cannot init leases", EACCES);
+ }
+
+ if (!smbd_notifyd_init(msg_ctx, interactive, &parent->notifyd)) {
+ exit_daemon("Samba cannot init notification", EACCES);
}
- if (!smbd_parent_notify_init(NULL, msg_ctx, ev_ctx)) {
+ if (!cleanupd_init(msg_ctx, interactive, &parent->cleanupd)) {
+ exit_daemon("Samba cannot init the cleanupd", EACCES);
+ }
+
+ if (!messaging_parent_dgm_cleanup_init(msg_ctx)) {
exit(1);
}
+ if (!smbd_scavenger_init(NULL, msg_ctx, ev_ctx)) {
+ exit_daemon("Samba cannot init scavenging", EACCES);
+ }
+
if (!serverid_parent_init(ev_ctx)) {
- exit(1);
+ exit_daemon("Samba cannot init server id", EACCES);
}
if (!W_ERROR_IS_OK(registry_init_full()))
- exit(1);
+ exit_daemon("Samba cannot init registry", EACCES);
/* Open the share_info.tdb here, so we don't have to open
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()) {
- DEBUG(0,("ERROR: failed to load share info db.\n"));
- exit(1);
+ exit_daemon("ERROR: failed to load share info db.", EACCES);
}
status = init_system_session_info();
}
status = smbXsrv_open_global_init();
if (!NT_STATUS_IS_OK(status)) {
- exit(1);
+ exit_daemon("Samba cannot init global open", map_errno_from_nt_status(status));
+ }
+
+ 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",
+ nt_errstr(status));
+ return -1;
+ }
}
/* This MUST be done before start_epmd() because otherwise
* start_epmd() forks and races against dcesrv_ep_setup() to
* call directory_create_or_exist() */
- if (!directory_create_or_exist(lp_ncalrpc_dir(), geteuid(), 0755)) {
+ if (!directory_create_or_exist(lp_ncalrpc_dir(), 0755)) {
DEBUG(0, ("Failed to create pipe directory %s - %s\n",
lp_ncalrpc_dir(), strerror(errno)));
return -1;
}
if (!dcesrv_ep_setup(ev_ctx, msg_ctx)) {
- exit(1);
+ exit_daemon("Samba cannot setup ep pipe", EACCES);
+ }
+
+ if (is_daemon && !interactive) {
+ daemon_ready("smbd");
}
/* only start other daemons if we are running as a daemon
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(1);
+ 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)) {
/* 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
+ Only do this on a pipe or socket, no other device.
*/
- tevent_add_fd(ev_ctx, parent, 0, TEVENT_FD_READ, smbd_stdin_handler, NULL);
+ struct stat st;
+ if (fstat(0, &st) != 0) {
+ return false;
+ }
+ if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) {
+ tevent_add_fd(ev_ctx,
+ parent,
+ 0,
+ TEVENT_FD_READ,
+ smbd_stdin_handler,
+ NULL);
+ }
}
smbd_parent_loop(ev_ctx, parent);