/* initialise a nbt_dgram_socket. The event_ctx is optional, if provided then operations will use that event context */ struct nbt_dgram_socket *nbt_dgram_socket_init(TALLOC_CTX *mem_ctx, struct tevent_context *event_ctx) { struct nbt_dgram_socket *dgmsock; NTSTATUS status; dgmsock = talloc(mem_ctx, struct nbt_dgram_socket); if (dgmsock == NULL) goto failed; dgmsock->event_ctx = event_ctx; if (dgmsock->event_ctx == NULL) goto failed; status = socket_create("ip", SOCKET_TYPE_DGRAM, &dgmsock->sock, 0); if (!NT_STATUS_IS_OK(status)) goto failed; socket_set_option(dgmsock->sock, "SO_BROADCAST", "1"); talloc_steal(dgmsock, dgmsock->sock); dgmsock->fde = tevent_add_fd(dgmsock->event_ctx, dgmsock, socket_get_fd(dgmsock->sock), 0, dgm_socket_handler, dgmsock); dgmsock->send_queue = NULL; dgmsock->incoming.handler = NULL; dgmsock->mailslot_handlers = NULL; return dgmsock; failed: talloc_free(dgmsock); return NULL; }
static void setup_handlers(struct tevent_context *ev, int from_parent_fd) { struct tevent_fd *fde = NULL; struct tevent_signal *se = NULL; fde = tevent_add_fd(ev, ev, from_parent_fd, TEVENT_FD_READ, prefork_pipe_handler, NULL); if (fde == NULL) { smb_panic("Failed to add fd handler after fork"); } se = tevent_add_signal(ev, ev, SIGHUP, 0, sighup_signal_handler, NULL); if (se == NULL) { smb_panic("Failed to add SIGHUP handler after fork"); } se = tevent_add_signal(ev, ev, SIGTERM, 0, sigterm_signal_handler, NULL); if (se == NULL) { smb_panic("Failed to add SIGTERM handler after fork"); } }
/* setup the inotify handle - called the first time a watch is added on this context */ static NTSTATUS inotify_setup(struct sys_notify_context *ctx) { struct inotify_private *in; if (!lp_parm_bool(-1, "notify", "inotify", True)) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } in = talloc(ctx, struct inotify_private); NT_STATUS_HAVE_NO_MEMORY(in); in->fd = inotify_init(); if (in->fd == -1) { DEBUG(0,("Failed to init inotify - %s\n", strerror(errno))); talloc_free(in); return map_nt_error_from_unix(errno); } in->ctx = ctx; in->watches = NULL; ctx->private_data = in; talloc_set_destructor(in, inotify_destructor); /* add a event waiting for the inotify fd to be readable */ tevent_add_fd(ctx->ev, in, in->fd, TEVENT_FD_READ, inotify_handler, in); return NT_STATUS_OK; }
static void mock_server_child(void *data) { struct mock_server *mock = data; struct tevent_context *loop; struct sbus_connection *server; bool stop_server = false; TALLOC_CTX *ctx; ctx = talloc_new(NULL); loop = tevent_context_init(ctx); verify_eq (sbus_new_server(ctx, loop, mock->dbus_address, false, &server, on_accept_connection, mock), EOK); tevent_add_fd(loop, ctx, mock->sync_fds[1], TEVENT_FD_READ, on_sync_fd_written, &stop_server); /* Synchronization point: test_dbus_setup_mock() should connect */ verify_eq (write(mock->sync_fds[1], "X", 1), 1); /* Do the loop */ while(!stop_server) { verify_eq (tevent_loop_once(loop), 0); } /* TODO: sbus doesn't support cleanup of a server */ talloc_free(ctx); }
static bool init_aio_threadpool(struct vfs_handle_struct *handle) { struct fd_event *sock_event = NULL; int ret = 0; int num_threads; if (pool) { return true; } num_threads = aio_get_num_threads(handle); ret = pthreadpool_init(num_threads, &pool); if (ret) { errno = ret; return false; } sock_event = tevent_add_fd(server_event_context(), NULL, pthreadpool_signal_fd(pool), TEVENT_FD_READ, aio_pthread_handle_completion, NULL); if (sock_event == NULL) { pthreadpool_destroy(pool); pool = NULL; return false; } DEBUG(10,("init_aio_threadpool: initialized with up to %d threads\n", num_threads)); return true; }
static PyObject *py_tevent_context_add_fd(TeventContext_Object *self, PyObject *args) { int fd, flags; PyObject *handler; struct tevent_fd *tfd; TeventFd_Object *ret; if (!PyArg_ParseTuple(args, "iiO", &fd, &flags, &handler)) return NULL; tfd = tevent_add_fd(self->ev, NULL, fd, flags, py_fd_handler, handler); if (tfd == NULL) { PyErr_SetNone(PyExc_RuntimeError); return NULL; } ret = PyObject_New(TeventFd_Object, &TeventFd_Type); if (ret == NULL) { talloc_free(tfd); return NULL; } ret->fd = tfd; return (PyObject *)ret; }
static bool init_aio_linux(struct vfs_handle_struct *handle) { struct tevent_timer *te = NULL; if (event_fd != -1) { /* Already initialized. */ return true; } /* Schedule a shutdown event for 30 seconds from now. */ te = tevent_add_timer(handle->conn->sconn->ev_ctx, NULL, timeval_current_ofs(30, 0), aio_linux_housekeeping, NULL); if (te == NULL) { goto fail; } event_fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); if (event_fd == -1) { goto fail; } aio_read_event = tevent_add_fd(server_event_context(), NULL, event_fd, TEVENT_FD_READ, aio_linux_done, NULL); if (aio_read_event == NULL) { goto fail; } if (io_queue_init(lp_aio_max_threads(), &io_ctx)) { goto fail; } DEBUG(10,("init_aio_linux: initialized with up to %d events\n", (int)lp_aio_max_threads())); return true; fail: DEBUG(10,("init_aio_linux: initialization failed\n")); TALLOC_FREE(te); TALLOC_FREE(aio_read_event); if (event_fd != -1) { close(event_fd); event_fd = -1; } memset(&io_ctx, '\0', sizeof(io_ctx)); return false; }
static bool py_cli_state_setup_ev(struct py_cli_state *self) { struct py_cli_thread *t = NULL; int ret; self->ev = tevent_context_init_byname(NULL, "poll_mt"); if (self->ev == NULL) { goto fail; } samba_tevent_set_debug(self->ev, "pylibsmb_tevent_mt"); tevent_set_trace_callback(self->ev, py_cli_state_trace_callback, self); self->thread_state = talloc_zero(NULL, struct py_cli_thread); if (self->thread_state == NULL) { goto fail; } t = self->thread_state; ret = pipe(t->shutdown_pipe); if (ret == -1) { goto fail; } t->shutdown_fde = tevent_add_fd( self->ev, self->ev, t->shutdown_pipe[0], TEVENT_FD_READ, py_cli_state_shutdown_handler, self); if (t->shutdown_fde == NULL) { goto fail; } PyEval_InitThreads(); ret = pthread_create(&t->id, NULL, py_cli_state_poll_thread, self); if (ret != 0) { goto fail; } talloc_set_destructor(self->thread_state, py_cli_thread_destructor); return true; fail: if (t != NULL) { TALLOC_FREE(t->shutdown_fde); if (t->shutdown_pipe[0] != -1) { close(t->shutdown_pipe[0]); t->shutdown_pipe[0] = -1; } if (t->shutdown_pipe[1] != -1) { close(t->shutdown_pipe[1]); t->shutdown_pipe[1] = -1; } } TALLOC_FREE(self->thread_state); TALLOC_FREE(self->ev); return false; }
/* called to create a new server task */ static void standard_new_task(struct tevent_context *ev, struct loadparm_context *lp_ctx, const char *service_name, void (*new_task)(struct tevent_context *, struct loadparm_context *lp_ctx, struct server_id , void *), void *private_data) { pid_t pid; struct tevent_context *ev2; pid = fork(); if (pid != 0) { /* parent or error code ... go back to the event loop */ return; } pid = getpid(); /* This is now the child code. We need a completely new event_context to work with */ ev2 = s4_event_context_init(NULL); /* setup this as the default context */ s4_event_context_set_default(ev2); /* the service has given us a private pointer that encapsulates the context it needs for this new connection - everything else will be freed */ talloc_steal(ev2, private_data); /* this will free all the listening sockets and all state that is not associated with this new connection */ talloc_free(ev); /* ldb/tdb need special fork handling */ ldb_wrap_fork_hook(); tevent_add_fd(ev2, ev2, child_pipe[0], TEVENT_FD_READ, standard_pipe_handler, NULL); close(child_pipe[1]); /* Ensure that the forked children do not expose identical random streams */ set_need_random_reseed(); setproctitle("task %s server_id[%d]", service_name, pid); /* setup this new task. Cluster ID is PID based for this process modal */ new_task(ev2, lp_ctx, cluster_id(pid, 0), private_data); /* we can't return to the top level here, as that event context is gone, so we now process events in the new event context until there are no more to process */ event_loop_wait(ev2); talloc_free(ev2); exit(0); }
bool setup_named_pipe_socket(const char *pipe_name, struct tevent_context *ev_ctx, struct messaging_context *msg_ctx) { struct dcerpc_ncacn_listen_state *state; struct tevent_fd *fde; int rc; state = talloc(ev_ctx, struct dcerpc_ncacn_listen_state); if (!state) { DEBUG(0, ("Out of memory\n")); return false; } state->ep.name = talloc_strdup(state, pipe_name); if (state->ep.name == NULL) { DEBUG(0, ("Out of memory\n")); goto out; } state->fd = create_named_pipe_socket(pipe_name); if (state->fd == -1) { goto out; } rc = listen(state->fd, 5); if (rc < 0) { DEBUG(0, ("Failed to listen on pipe socket %s: %s\n", pipe_name, strerror(errno))); goto out; } state->ev_ctx = ev_ctx; state->msg_ctx = msg_ctx; DEBUG(10, ("Openened pipe socket fd %d for %s\n", state->fd, pipe_name)); fde = tevent_add_fd(ev_ctx, state, state->fd, TEVENT_FD_READ, named_pipe_listener, state); if (!fde) { DEBUG(0, ("Failed to add event handler!\n")); goto out; } tevent_fd_set_auto_close(fde); return true; out: if (state->fd != -1) { close(state->fd); } TALLOC_FREE(state); return false; }
static bool nmbd_setup_stdin_handler(struct messaging_context *msg, bool foreground) { if (foreground) { /* 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 */ tevent_add_fd(nmbd_event_context(), nmbd_event_context(), 0, TEVENT_FD_READ, nmbd_stdin_handler, msg); } return true; }
static bool test_event_context_threaded(struct torture_context *test, const void *test_data) { struct tevent_context *ev; struct tevent_timer *te; struct tevent_fd *fde; pthread_t poll_thread; int fds[2]; int ret; char c = 0; ev = tevent_context_init_byname(test, "poll_mt"); torture_assert(test, ev != NULL, "poll_mt not supported"); tevent_set_trace_callback(ev, test_event_threaded_trace, NULL); te = tevent_add_timer(ev, ev, timeval_current_ofs(5, 0), test_event_threaded_timer, NULL); torture_assert(test, te != NULL, "Could not add timer"); ret = pthread_create(&poll_thread, NULL, test_event_poll_thread, ev); torture_assert(test, ret == 0, "Could not create poll thread"); ret = pipe(fds); torture_assert(test, ret == 0, "Could not create pipe"); poll(NULL, 0, 100); test_event_threaded_lock(); fde = tevent_add_fd(ev, ev, fds[0], TEVENT_FD_READ, test_event_threaded_read_handler, &fds[0]); torture_assert(test, fde != NULL, "Could not add fd event"); test_event_threaded_unlock(); poll(NULL, 0, 100); write(fds[1], &c, 1); poll(NULL, 0, 100); test_event_threaded_lock(); do_shutdown = true; test_event_threaded_unlock(); write(fds[1], &c, 1); ret = pthread_join(poll_thread, NULL); torture_assert(test, ret == 0, "pthread_join failed"); return true; }
/* called to create a new server task */ static void standard_new_task(struct tevent_context *ev, struct loadparm_context *lp_ctx, const char *service_name, void (*new_task)(struct tevent_context *, struct loadparm_context *lp_ctx, struct server_id , void *), void *private_data) { pid_t pid; pid = fork(); if (pid != 0) { /* parent or error code ... go back to the event loop */ return; } pid = getpid(); /* this will free all the listening sockets and all state that is not associated with this new connection */ if (tevent_re_initialise(ev) != 0) { smb_panic("Failed to re-initialise tevent after fork"); } /* ldb/tdb need special fork handling */ ldb_wrap_fork_hook(); tevent_add_fd(ev, ev, child_pipe[0], TEVENT_FD_READ, standard_pipe_handler, NULL); close(child_pipe[1]); /* Ensure that the forked children do not expose identical random streams */ set_need_random_reseed(); setproctitle("task %s server_id[%d]", service_name, (int)pid); /* setup this new task. Cluster ID is PID based for this process modal */ new_task(ev, lp_ctx, cluster_id(pid, 0), private_data); /* we can't return to the top level here, as that event context is gone, so we now process events in the new event context until there are no more to process */ event_loop_wait(ev); talloc_free(ev); exit(0); }
struct kernel_oplocks *irix_init_kernel_oplocks(struct smbd_server_connection *sconn) { struct kernel_oplocks *_ctx; struct irix_oplocks_context *ctx; int pfd[2]; if (!irix_oplocks_available()) return NULL; _ctx = talloc_zero(sconn, struct kernel_oplocks); if (!_ctx) { return NULL; } ctx = talloc_zero(_ctx, struct irix_oplocks_context); if (!ctx) { talloc_free(_ctx); return NULL; } _ctx->ops = &irix_koplocks; _ctx->private_data = ctx; ctx->ctx = _ctx; ctx->sconn = sconn; if(pipe(pfd) != 0) { talloc_free(_ctx); DEBUG(0,("setup_kernel_oplock_pipe: Unable to create pipe. " "Error was %s\n", strerror(errno) )); return False; } ctx->read_fd = pfd[0]; ctx->write_fd = pfd[1]; ctx->read_fde = tevent_add_fd(sconn->ev_ctx, ctx, ctx->read_fd, TEVENT_FD_READ, irix_oplocks_read_fde_handler, ctx); return _ctx; }
/* setup the fd used by the queue */ int ctdb_queue_set_fd(struct ctdb_queue *queue, int fd) { queue->fd = fd; talloc_free(queue->fde); queue->fde = NULL; if (fd != -1) { queue->fde = tevent_add_fd(queue->ctdb->ev, queue, fd, TEVENT_FD_READ, queue_io_handler, queue); if (queue->fde == NULL) { return -1; } tevent_fd_set_auto_close(queue->fde); if (queue->out_queue) { TEVENT_FD_WRITEABLE(queue->fde); } } return 0; }
static bool init_aio_threadpool(struct event_context *ev_ctx, struct pthreadpool **pp_pool, void (*completion_fn)(struct event_context *, struct fd_event *, uint16, void *)) { struct fd_event *sock_event = NULL; int ret = 0; if (*pp_pool) { return true; } ret = pthreadpool_init(aio_pending_size, pp_pool); if (ret) { errno = ret; return false; } sock_event = tevent_add_fd(ev_ctx, NULL, pthreadpool_signal_fd(*pp_pool), TEVENT_FD_READ, completion_fn, NULL); if (sock_event == NULL) { pthreadpool_destroy(*pp_pool); *pp_pool = NULL; return false; } DEBUG(10,("init_aio_threadpool: initialized with up to %d threads\n", aio_pending_size)); return true; }
static bool nmbd_setup_stdin_handler(struct messaging_context *msg, bool foreground) { if (foreground) { /* 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. */ struct stat st; if (fstat(0, &st) != 0) { return false; } if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) { tevent_add_fd(nmbd_event_context(), nmbd_event_context(), 0, TEVENT_FD_READ, nmbd_stdin_handler, msg); } } return true; }
static bool init_aio_threadpool(struct tevent_context *ev_ctx, struct pthreadpool_pipe **pp_pool, void (*completion_fn)(struct tevent_context *, struct tevent_fd *, uint16_t, void *)) { struct tevent_fd *sock_event = NULL; int ret = 0; if (*pp_pool) { return true; } ret = pthreadpool_pipe_init(lp_aio_max_threads(), pp_pool); if (ret) { errno = ret; return false; } sock_event = tevent_add_fd(ev_ctx, NULL, pthreadpool_pipe_signal_fd(*pp_pool), TEVENT_FD_READ, completion_fn, NULL); if (sock_event == NULL) { pthreadpool_pipe_destroy(*pp_pool); *pp_pool = NULL; return false; } DEBUG(10,("init_aio_threadpool: initialized with up to %d threads\n", (int)lp_aio_max_threads())); return true; }
/* run a command as a child process, with a timeout. any stdout/stderr from the child will appear in the Samba logs with the specified log levels */ struct tevent_req *samba_runcmd_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct timeval endtime, int stdout_log_level, int stderr_log_level, const char * const *argv0, ...) { struct tevent_req *req; struct samba_runcmd_state *state; int p1[2], p2[2], p3[2]; char **argv; va_list ap; if (argv0 == NULL) { return NULL; } req = tevent_req_create(mem_ctx, &state, struct samba_runcmd_state); if (req == NULL) { return NULL; } state->stdout_log_level = stdout_log_level; state->stderr_log_level = stderr_log_level; state->fd_stdin = -1; state->arg0 = talloc_strdup(state, argv0[0]); if (tevent_req_nomem(state->arg0, req)) { return tevent_req_post(req, ev); } if (pipe(p1) != 0) { tevent_req_error(req, errno); return tevent_req_post(req, ev); } if (pipe(p2) != 0) { close(p1[0]); close(p1[1]); tevent_req_error(req, errno); return tevent_req_post(req, ev); } if (pipe(p3) != 0) { close(p1[0]); close(p1[1]); close(p2[0]); close(p2[1]); tevent_req_error(req, errno); return tevent_req_post(req, ev); } state->tfork = tfork_create(); if (state->tfork == NULL) { close(p1[0]); close(p1[1]); close(p2[0]); close(p2[1]); close(p3[0]); close(p3[1]); tevent_req_error(req, errno); return tevent_req_post(req, ev); } state->pid = tfork_child_pid(state->tfork); if (state->pid != 0) { /* the parent */ close(p1[1]); close(p2[1]); close(p3[0]); state->fd_stdout = p1[0]; state->fd_stderr = p2[0]; state->fd_stdin = p3[1]; state->fd_status = tfork_event_fd(state->tfork); set_blocking(state->fd_stdout, false); set_blocking(state->fd_stderr, false); set_blocking(state->fd_stdin, false); set_blocking(state->fd_status, false); smb_set_close_on_exec(state->fd_stdin); smb_set_close_on_exec(state->fd_stdout); smb_set_close_on_exec(state->fd_stderr); smb_set_close_on_exec(state->fd_status); tevent_req_set_cleanup_fn(req, samba_runcmd_cleanup_fn); state->fde_stdout = tevent_add_fd(ev, state, state->fd_stdout, TEVENT_FD_READ, samba_runcmd_io_handler, req); if (tevent_req_nomem(state->fde_stdout, req)) { close(state->fd_stdout); close(state->fd_stderr); close(state->fd_status); return tevent_req_post(req, ev); } tevent_fd_set_auto_close(state->fde_stdout); state->fde_stderr = tevent_add_fd(ev, state, state->fd_stderr, TEVENT_FD_READ, samba_runcmd_io_handler, req); if (tevent_req_nomem(state->fde_stdout, req)) { close(state->fd_stdout); close(state->fd_stderr); close(state->fd_status); return tevent_req_post(req, ev); } tevent_fd_set_auto_close(state->fde_stderr); state->fde_status = tevent_add_fd(ev, state, state->fd_status, TEVENT_FD_READ, samba_runcmd_io_handler, req); if (tevent_req_nomem(state->fde_stdout, req)) { close(state->fd_stdout); close(state->fd_stderr); close(state->fd_status); return tevent_req_post(req, ev); } tevent_fd_set_auto_close(state->fde_status); if (!timeval_is_zero(&endtime)) { tevent_req_set_endtime(req, ev, endtime); } return req; } /* the child */ close(p1[0]); close(p2[0]); close(p3[1]); close(0); close(1); close(2); /* we want to ensure that all of the network sockets we had open are closed */ tevent_re_initialise(ev); /* setup for logging to go to the parents debug log */ dup2(p3[0], 0); dup2(p1[1], 1); dup2(p2[1], 2); close(p1[1]); close(p2[1]); close(p3[0]); argv = str_list_copy(state, discard_const_p(const char *, argv0)); if (!argv) { fprintf(stderr, "Out of memory in child\n"); _exit(255); } va_start(ap, argv0); while (1) { const char **l; char *arg = va_arg(ap, char *); if (arg == NULL) break; l = discard_const_p(const char *, argv); l = str_list_add(l, arg); if (l == NULL) { fprintf(stderr, "Out of memory in child\n"); _exit(255); } argv = discard_const_p(char *, l); } va_end(ap); (void)execvp(state->arg0, argv); fprintf(stderr, "Failed to exec child - %s\n", strerror(errno)); _exit(255); return NULL; }
static bool smbd_open_one_socket(struct smbd_parent_context *parent, struct tevent_context *ev_ctx, struct messaging_context *msg_ctx, const struct sockaddr_storage *ifss, uint16_t port) { struct smbd_open_socket *s; s = talloc(parent, struct smbd_open_socket); if (!s) { return false; } 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_once_socket: open_socket_in: " "%s\n", strerror(errno))); TALLOC_FREE(s); /* * We ignore an error here, as we've done before */ return true; } /* ready to listen */ set_socket_options(s->fd, "SO_KEEPALIVE"); set_socket_options(s->fd, lp_socket_options()); /* Set server socket to * non-blocking for the accept. */ set_blocking(s->fd, False); if (listen(s->fd, SMBD_LISTEN_BACKLOG) == -1) { DEBUG(0,("open_sockets_smbd: listen: " "%s\n", strerror(errno))); close(s->fd); TALLOC_FREE(s); return false; } s->msg_ctx = msg_ctx; s->fde = tevent_add_fd(ev_ctx, s, s->fd, TEVENT_FD_READ, smbd_accept_connection, s); if (!s->fde) { DEBUG(0,("open_sockets_smbd: " "tevent_add_fd: %s\n", strerror(errno))); close(s->fd); TALLOC_FREE(s); return false; } tevent_fd_set_close_fn(s->fde, smbd_open_socket_close_fn); DLIST_ADD_END(parent->sockets, s, struct smbd_open_socket *); return true; }
static bool fdpass2_parent(pid_t child_pid, int ready_fd) { struct tevent_context *ev = NULL; struct messaging_context *msg_ctx = NULL; bool retval = false; int up_pipe[2]; int down_pipe[2]; int pass_fds[2] = { 0 }; int ret; NTSTATUS status; struct server_id dst; TALLOC_CTX *frame = talloc_stackframe(); uint8_t c1 = 1, c2, c; ssize_t bytes; struct iovec iov; DATA_BLOB blob; struct tevent_fd *child_done_fde; struct child_done_state child_state; ev = samba_tevent_context_init(frame); if (ev == NULL) { fprintf(stderr, "parent: tevent_context_init failed\n"); goto done; } msg_ctx = messaging_init(ev, ev); if (msg_ctx == NULL) { fprintf(stderr, "parent: messaging_init failed\n"); goto done; } /* wait util the child is ready to receive messages */ bytes = read(ready_fd, &c, 1); if (bytes != 1) { perror("parent: read from ready_fd failed"); goto done; } ret = pipe(up_pipe); if (ret != 0) { perror("parent: pipe failed for up_pipe"); goto done; } ret = pipe(down_pipe); if (ret != 0) { perror("parent: pipe failed for down_pipe"); goto done; } child_state.fd = ready_fd; child_state.done = false; child_done_fde = tevent_add_fd(ev, ev, ready_fd, TEVENT_FD_READ, child_done_cb, &child_state); if (child_done_fde == NULL) { fprintf(stderr, "parent: failed tevent_add_fd for child done\n"); goto done; } pass_fds[0] = up_pipe[0]; pass_fds[1] = down_pipe[1]; dst = messaging_server_id(msg_ctx); dst.pid = child_pid; /* * Send a certain payload with the fds, to test to test * that fd-passing works when we have fragmentation and * re-assembly of the datagrams. */ blob = data_blob_talloc_zero(frame, 1000*1000); iov.iov_base = blob.data; iov.iov_len = blob.length; status = messaging_send_iov(msg_ctx, dst, MSG_TORTURE_FDPASS2, &iov, 1, pass_fds, 2); if (!NT_STATUS_IS_OK(status)) { fprintf(stderr, "parent: messaging_send_iov failed: %s\n", nt_errstr(status)); goto done; } printf("parent: waiting for child to confirm\n"); while (!child_state.done) { ret = tevent_loop_once(ev); if (ret != 0) { fprintf(stderr, "parent: tevent_loop_once failed\n"); goto done; } } printf("parent: child confirmed\n"); close(up_pipe[0]); close(down_pipe[1]); bytes = write(up_pipe[1], &c1, 1); if (bytes != 1) { perror("parent: write to up pipe failed"); goto done; } bytes = read(down_pipe[0], &c2, 1); if (bytes != 1) { perror("parent: read from down pipe failed"); goto done; } if (c1 != c2) { fprintf(stderr, "parent: c1[%d] != c2[%d]\n", c1, c2); goto done; } ret = waitpid(child_pid, NULL, 0); if (ret == -1) { perror("parent: waitpid failed"); goto done; } retval = true; done: TALLOC_FREE(frame); return retval; }
static bool smbd_scavenger_start(struct smbd_scavenger_state *state) { struct server_id self = messaging_server_id(state->msg); struct tevent_fd *fde = NULL; int fds[2]; int ret; uint64_t unique_id; bool ok; SMB_ASSERT(server_id_equal(&state->parent_id, &self)); if (smbd_scavenger_running(state)) { DEBUG(10, ("scavenger %s already running\n", server_id_str(talloc_tos(), state->scavenger_id))); return true; } if (state->scavenger_id != NULL) { DEBUG(10, ("scavenger zombie %s, cleaning up\n", server_id_str(talloc_tos(), state->scavenger_id))); TALLOC_FREE(state->scavenger_id); } state->scavenger_id = talloc_zero(state, struct server_id); if (state->scavenger_id == NULL) { DEBUG(2, ("Out of memory\n")); goto fail; } talloc_set_destructor(state->scavenger_id, smbd_scavenger_server_id_destructor); ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds); if (ret == -1) { DEBUG(2, ("socketpair failed: %s", strerror(errno))); goto fail; } smb_set_close_on_exec(fds[0]); smb_set_close_on_exec(fds[1]); unique_id = serverid_get_random_unique_id(); ret = fork(); if (ret == -1) { int err = errno; close(fds[0]); close(fds[1]); DEBUG(0, ("fork failed: %s", strerror(err))); goto fail; } if (ret == 0) { /* child */ NTSTATUS status; close(fds[0]); am_parent = NULL; set_my_unique_id(unique_id); status = reinit_after_fork(state->msg, state->ev, true); if (!NT_STATUS_IS_OK(status)) { DEBUG(2, ("reinit_after_fork failed: %s\n", nt_errstr(status))); exit_server("reinit_after_fork failed"); return false; } prctl_set_comment("smbd-scavenger"); state->am_scavenger = true; *state->scavenger_id = messaging_server_id(state->msg); scavenger_setup_sig_term_handler(state->ev); serverid_register(*state->scavenger_id, FLAG_MSG_GENERAL); ok = scavenger_say_hello(fds[1], *state->scavenger_id); if (!ok) { DEBUG(2, ("scavenger_say_hello failed\n")); exit_server("scavenger_say_hello failed"); return false; } fde = tevent_add_fd(state->ev, state->scavenger_id, fds[1], TEVENT_FD_READ, smbd_scavenger_parent_dead, state); if (fde == NULL) { DEBUG(2, ("tevent_add_fd(smbd_scavenger_parent_dead) " "failed\n")); exit_server("tevent_add_fd(smbd_scavenger_parent_dead) " "failed"); return false; } tevent_fd_set_auto_close(fde); ret = smbd_scavenger_main(state); DEBUG(10, ("scavenger ended: %d\n", ret)); exit_server_cleanly("scavenger ended"); return false; } /* parent */ close(fds[1]); ok = scavenger_wait_hello(fds[0], state->scavenger_id); if (!ok) { close(fds[0]); goto fail; } fde = tevent_add_fd(state->ev, state->scavenger_id, fds[0], TEVENT_FD_READ, smbd_scavenger_done, state); if (fde == NULL) { close(fds[0]); goto fail; } tevent_fd_set_auto_close(fde); return true; fail: TALLOC_FREE(state->scavenger_id); return false; }
/* main server. */ static int binary_smbd_main(const char *binary_name, int argc, const char *argv[]) { bool opt_daemon = false; bool opt_interactive = false; int opt; poptContext pc; #define _MODULE_PROTO(init) extern NTSTATUS init(void); STATIC_service_MODULES_PROTO; init_module_fn static_init[] = { STATIC_service_MODULES }; init_module_fn *shared_init; struct tevent_context *event_ctx; uint16_t stdin_event_flags; NTSTATUS status; const char *model = "standard"; int max_runtime = 0; enum { OPT_DAEMON = 1000, OPT_INTERACTIVE, OPT_PROCESS_MODEL, OPT_SHOW_BUILD }; struct poptOption long_options[] = { POPT_AUTOHELP {"daemon", 'D', POPT_ARG_NONE, NULL, OPT_DAEMON, "Become a daemon (default)", NULL }, {"interactive", 'i', POPT_ARG_NONE, NULL, OPT_INTERACTIVE, "Run interactive (not a daemon)", NULL}, {"model", 'M', POPT_ARG_STRING, NULL, OPT_PROCESS_MODEL, "Select process model", "MODEL"}, {"maximum-runtime",0, POPT_ARG_INT, &max_runtime, 0, "set maximum runtime of the server process, till autotermination", "seconds"}, {"show-build", 'b', POPT_ARG_NONE, NULL, OPT_SHOW_BUILD, "show build info", NULL }, POPT_COMMON_SAMBA POPT_COMMON_VERSION { NULL } }; pc = poptGetContext(binary_name, argc, argv, long_options, 0); while((opt = poptGetNextOpt(pc)) != -1) { switch(opt) { case OPT_DAEMON: opt_daemon = true; break; case OPT_INTERACTIVE: opt_interactive = true; break; case OPT_PROCESS_MODEL: model = poptGetOptArg(pc); break; case OPT_SHOW_BUILD: show_build(); break; default: fprintf(stderr, "\nInvalid option %s: %s\n\n", poptBadOption(pc, 0), poptStrerror(opt)); poptPrintUsage(pc, stderr, 0); return 1; } } if (opt_daemon && opt_interactive) { fprintf(stderr,"\nERROR: " "Option -i|--interactive is not allowed together with -D|--daemon\n\n"); poptPrintUsage(pc, stderr, 0); return 1; } else if (!opt_interactive) { /* default is --daemon */ opt_daemon = true; } poptFreeContext(pc); setup_logging(binary_name, opt_interactive?DEBUG_STDOUT:DEBUG_FILE); setup_signals(); /* we want total control over the permissions on created files, so set our umask to 0 */ umask(0); DEBUG(0,("%s version %s started.\n", binary_name, SAMBA_VERSION_STRING)); DEBUGADD(0,("Copyright Andrew Tridgell and the Samba Team 1992-2011\n")); if (sizeof(uint16_t) < 2 || sizeof(uint32_t) < 4 || sizeof(uint64_t) < 8) { DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n")); DEBUGADD(0,("sizeof(uint16_t) = %u, sizeof(uint32_t) %u, sizeof(uint64_t) = %u\n", (unsigned int)sizeof(uint16_t), (unsigned int)sizeof(uint32_t), (unsigned int)sizeof(uint64_t))); return 1; } if (opt_daemon) { DEBUG(3,("Becoming a daemon.\n")); become_daemon(true, false, false); } cleanup_tmp_files(cmdline_lp_ctx); if (!directory_exist(lpcfg_lockdir(cmdline_lp_ctx))) { mkdir(lpcfg_lockdir(cmdline_lp_ctx), 0755); } pidfile_create(lpcfg_piddir(cmdline_lp_ctx), binary_name); /* Set up a database to hold a random seed, in case we don't * have /dev/urandom */ if (!randseed_init(talloc_autofree_context(), cmdline_lp_ctx)) { return 1; } if (lpcfg_server_role(cmdline_lp_ctx) == ROLE_DOMAIN_CONTROLLER) { if (!open_schannel_session_store(talloc_autofree_context(), lpcfg_private_dir(cmdline_lp_ctx))) { DEBUG(0,("ERROR: Samba cannot open schannel store for secured NETLOGON operations.\n")); exit(1); } } gensec_init(); /* FIXME: */ ntptr_init(); /* FIXME: maybe run this in the initialization function of the spoolss RPC server instead? */ ntvfs_init(cmdline_lp_ctx); /* FIXME: maybe run this in the initialization functions of the SMB[,2] server instead? */ process_model_init(cmdline_lp_ctx); shared_init = load_samba_modules(NULL, "service"); run_init_functions(static_init); run_init_functions(shared_init); talloc_free(shared_init); /* the event context is the top level structure in smbd. Everything else should hang off that */ event_ctx = s4_event_context_init(talloc_autofree_context()); if (event_ctx == NULL) { DEBUG(0,("Initializing event context failed\n")); return 1; } if (opt_interactive) { /* terminate when stdin goes away */ stdin_event_flags = TEVENT_FD_READ; } else { /* stay alive forever */ stdin_event_flags = 0; } /* catch EOF on stdin */ #ifdef SIGTTIN signal(SIGTTIN, SIG_IGN); #endif tevent_add_fd(event_ctx, event_ctx, 0, stdin_event_flags, server_stdin_handler, discard_const(binary_name)); if (max_runtime) { DEBUG(0,("Called with maxruntime %d - current ts %llu\n", max_runtime, (unsigned long long) time(NULL))); tevent_add_timer(event_ctx, event_ctx, timeval_current_ofs(max_runtime, 0), max_runtime_handler, discard_const(binary_name)); } prime_ldb_databases(event_ctx); status = setup_parent_messaging(event_ctx, cmdline_lp_ctx); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Failed to setup parent messaging - %s\n", nt_errstr(status))); return 1; } DEBUG(0,("%s: using '%s' process model\n", binary_name, model)); status = server_service_startup(event_ctx, cmdline_lp_ctx, model, lpcfg_server_services(cmdline_lp_ctx)); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Starting Services failed - %s\n", nt_errstr(status))); return 1; } /* wait for events - this is where smbd sits for most of its life */ tevent_loop_wait(event_ctx); /* as everything hangs off this event context, freeing it should initiate a clean shutdown of all services */ talloc_free(event_ctx); return 0; }
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; bool log_stdout = false; char *ports = NULL; char *profile_level = NULL; int opt; poptContext pc; bool print_build_options = False; 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)"}, {"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 }; struct smbd_parent_context *parent = NULL; TALLOC_CTX *frame; NTSTATUS status; struct tevent_context *ev_ctx; 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, .become_root = smbd_become_root, .unbecome_root = smbd_unbecome_root, .exit_server = smbd_exit_server, .exit_server_cleanly = smbd_exit_server_cleanly, }; /* * Do this before any other talloc operation */ talloc_enable_null_tracking(); frame = talloc_stackframe(); setup_logging(argv[0], DEBUG_DEFAULT_STDOUT); smb_init_locale(); set_smbd_shim(&smbd_shim_fns); smbd_init_globals(); TimeInit(); #ifdef HAVE_SET_AUTH_PARAMETERS set_auth_parameters(argc,argv); #endif pc = poptGetContext("smbd", argc, argv, long_options, 0); 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; break; default: d_fprintf(stderr, "\nInvalid option %s: %s\n\n", poptBadOption(pc, 0), poptStrerror(opt)); poptPrintUsage(pc, stderr, 0); exit(1); } } poptFreeContext(pc); if (interactive) { Fork = False; log_stdout = True; } 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); } #ifdef HAVE_SETLUID /* needed for SecureWare on SCO */ setluid(0); #endif set_remote_machine_name("smbd", False); if (interactive && (DEBUGLEVEL >= 9)) { talloc_enable_leak_report(); } if (log_stdout && Fork) { DEBUG(0,("ERROR: Can't log to stdout (-S) unless daemon is in foreground (-F) or interactive (-i)\n")); exit(1); } /* we want to re-seed early to prevent time delays causing client problems at a later date. (tridge) */ generate_random_buffer(NULL, 0); /* get initial effective uid and gid */ sec_init(); /* make absolutely sure we run as root - to handle cases where people are crazy enough to have it setuid */ gain_root_privilege(); gain_root_group_privilege(); fault_setup(); dump_core_setup("smbd", lp_logfile(talloc_tos())); /* we are never interested in SIGPIPE */ BlockSignals(True,SIGPIPE); #if defined(SIGFPE) /* we are never interested in SIGFPE */ BlockSignals(True,SIGFPE); #endif #if defined(SIGUSR2) /* We are no longer interested in USR2 */ 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. */ BlockSignals(False, SIGHUP); BlockSignals(False, SIGUSR1); BlockSignals(False, SIGTERM); /* Ensure we leave no zombies until we * correctly set up child handling below. */ CatchChild(); /* we want total control over the permissions on created files, so set our umask to 0 */ umask(0); reopen_logs(); 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", (int)getuid(),(int)getgid(),(int)geteuid(),(int)getegid())); /* Output the build options to the debug log */ build_options(False); 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); } if (!lp_load_initial_only(get_dyn_CONFIGFILE())) { DEBUG(0, ("error opening config file '%s'\n", get_dyn_CONFIGFILE())); 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) { exit(1); } /* * Init the messaging context * FIXME: This should only call messaging_init() */ msg_ctx = server_messaging_context(); if (msg_ctx == NULL) { exit(1); } /* * Reloading of the printers will not work here as we don't have a * server info and rpc services set up. It will be called later. */ if (!reload_services(NULL, NULL, false)) { 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); } /* ...NOTE... Log files are working from this point! */ DEBUG(3,("loaded services\n")); init_structs(); if (!profile_setup(msg_ctx, False)) { DEBUG(0,("ERROR: failed to setup profiling\n")); return -1; } if (profile_level != NULL) { profiling_level = atoi(profile_level); } else { profiling_level = lp_smbd_profiling_level(); } set_profile_level(profiling_level, messaging_server_id(msg_ctx)); if (!is_daemon && !is_a_socket(0)) { if (!interactive) { DEBUG(3, ("Standard input is not a socket, " "assuming -D option\n")); } /* * Setting is_daemon here prevents us from eventually calling * the open_sockets_inetd() */ is_daemon = True; } if (is_daemon && !interactive) { DEBUG(3, ("Becoming a daemon.\n")); become_daemon(Fork, no_process_group, log_stdout); } #if HAVE_SETPGID /* * If we're interactive we want to set our own process group for * signal management. */ if (interactive && !no_process_group) setpgid( (pid_t)0, (pid_t)0); #endif if (!directory_exist(lp_lock_directory())) mkdir(lp_lock_directory(), 0755); if (!directory_exist(lp_pid_directory())) mkdir(lp_pid_directory(), 0755); if (is_daemon) pidfile_create(lp_pid_directory(), "smbd"); status = reinit_after_fork(msg_ctx, ev_ctx, false, NULL); if (!NT_STATUS_IS_OK(status)) { exit_daemon("reinit_after_fork() failed", map_errno_from_nt_status(status)); } if (!interactive) { /* * Do not initialize the parent-child-pipe before becoming a * daemon: this is used to detect a died parent in the child * process. */ status = init_before_fork(); if (!NT_STATUS_IS_OK(status)) { exit_daemon(nt_errstr(status), map_errno_from_nt_status(status)); } } parent = talloc_zero(ev_ctx, struct smbd_parent_context); if (!parent) { exit_server("talloc(struct smbd_parent_context) failed"); } parent->interactive = interactive; parent->ev_ctx = ev_ctx; parent->msg_ctx = msg_ctx; am_parent = parent; se = tevent_add_signal(parent->ev_ctx, parent, SIGTERM, 0, smbd_parent_sig_term_handler, parent); if (!se) { exit_server("failed to setup SIGTERM handler"); } se = tevent_add_signal(parent->ev_ctx, parent, SIGHUP, 0, smbd_parent_sig_hup_handler, parent); if (!se) { exit_server("failed to setup SIGHUP handler"); } /* Setup all the TDB's - including CLEAR_IF_FIRST tdb's. */ if (smbd_memcache() == NULL) { exit_daemon("no memcache available", EACCES); } memcache_set_global(smbd_memcache()); /* Initialise the password backed before the global_sam_sid to ensure that we fetch from ldap before we make a domain sid up */ if(!initialize_password_db(false, ev_ctx)) exit(1); if (!secrets_init()) { 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)) { exit_daemon("ERROR: Samba cannot open schannel store for secured NETLOGON operations.", EACCES); } TALLOC_FREE(lp_ctx); } if(!get_global_sam_sid()) { 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_daemon("Samba cannot init server context", EACCES); } status = smbXsrv_session_global_init(); if (!NT_STATUS_IS_OK(status)) { exit_daemon("Samba cannot init session context", EACCES); } status = smbXsrv_tcon_global_init(); if (!NT_STATUS_IS_OK(status)) { exit_daemon("Samba cannot init tcon context", EACCES); } if (!locking_init()) exit_daemon("Samba cannot init locking", EACCES); if (!leases_db_init(false)) { exit_daemon("Samba cannot init leases", EACCES); } if (!smbd_notifyd_init(msg_ctx, interactive)) { exit_daemon("Samba cannot init notification", 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_daemon("Samba cannot init server id", EACCES); } if (!W_ERROR_IS_OK(registry_init_full())) 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()) { exit_daemon("ERROR: failed to load share info db.", EACCES); } status = init_system_session_info(); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("ERROR: failed to setup system user info: %s.\n", nt_errstr(status))); return -1; } if (!init_guest_info()) { DEBUG(0,("ERROR: failed to setup guest info.\n")); return -1; } if (!file_init_global()) { DEBUG(0, ("ERROR: file_init_global() failed\n")); return -1; } status = smbXsrv_open_global_init(); if (!NT_STATUS_IS_OK(status)) { exit_daemon("Samba cannot init global open", map_errno_from_nt_status(status)); } /* 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(), 0755)) { DEBUG(0, ("Failed to create pipe directory %s - %s\n", lp_ncalrpc_dir(), strerror(errno))); return -1; } np_dir = talloc_asprintf(talloc_tos(), "%s/np", lp_ncalrpc_dir()); if (!np_dir) { DEBUG(0, ("%s: Out of memory\n", __location__)); return -1; } if (!directory_create_or_exist_strict(np_dir, geteuid(), 0700)) { DEBUG(0, ("Failed to create pipe directory %s - %s\n", np_dir, strerror(errno))); 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) { 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; /* inetd mode */ TALLOC_FREE(frame); /* Started from inetd. fd 0 is the socket. */ /* We will abort gracefully when the client or remote system goes away */ sock = dup(0); /* close stdin, stdout (if not logging to it), but not stderr */ close_low_fds(true, !debug_get_output_is_stdout(), false); #ifdef HAVE_ATEXIT atexit(killkids); #endif /* Stop zombies */ smbd_setup_sig_chld_handler(parent); smbd_process(ev_ctx, msg_ctx, sock, true); exit_server_cleanly(NULL); return(0); } 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 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. */ 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); exit_server_cleanly(NULL); TALLOC_FREE(frame); return(0); }
static int ibw_setup_cq_qp(struct ibw_conn *conn) { struct ibw_ctx_priv *pctx = talloc_get_type(conn->ctx->internal, struct ibw_ctx_priv); struct ibw_conn_priv *pconn = talloc_get_type(conn->internal, struct ibw_conn_priv); struct ibv_qp_init_attr init_attr; struct ibv_qp_attr attr; int rc; DEBUG(DEBUG_DEBUG, ("ibw_setup_cq_qp(cmid: %p)\n", pconn->cm_id)); /* init verbs */ pconn->verbs_channel = ibv_create_comp_channel(pconn->cm_id->verbs); if (!pconn->verbs_channel) { sprintf(ibw_lasterr, "ibv_create_comp_channel failed %d\n", errno); return -1; } DEBUG(DEBUG_DEBUG, ("created channel %p\n", pconn->verbs_channel)); pconn->verbs_channel_event = tevent_add_fd(pctx->ectx, NULL, /* not pconn or conn */ pconn->verbs_channel->fd, TEVENT_FD_READ, ibw_event_handler_verbs, conn); pconn->pd = ibv_alloc_pd(pconn->cm_id->verbs); if (!pconn->pd) { sprintf(ibw_lasterr, "ibv_alloc_pd failed %d\n", errno); return -1; } DEBUG(DEBUG_DEBUG, ("created pd %p\n", pconn->pd)); /* init mr */ if (ibw_init_memory(conn)) return -1; /* init cq */ pconn->cq = ibv_create_cq(pconn->cm_id->verbs, pctx->opts.max_recv_wr + pctx->opts.max_send_wr, conn, pconn->verbs_channel, 0); if (pconn->cq==NULL) { sprintf(ibw_lasterr, "ibv_create_cq failed\n"); return -1; } rc = ibv_req_notify_cq(pconn->cq, 0); if (rc) { sprintf(ibw_lasterr, "ibv_req_notify_cq failed with %d\n", rc); return rc; } /* init qp */ memset(&init_attr, 0, sizeof(init_attr)); init_attr.cap.max_send_wr = pctx->opts.max_send_wr; init_attr.cap.max_recv_wr = pctx->opts.max_recv_wr; init_attr.cap.max_recv_sge = 1; init_attr.cap.max_send_sge = 1; init_attr.qp_type = IBV_QPT_RC; init_attr.send_cq = pconn->cq; init_attr.recv_cq = pconn->cq; rc = rdma_create_qp(pconn->cm_id, pconn->pd, &init_attr); if (rc) { sprintf(ibw_lasterr, "rdma_create_qp failed with %d\n", rc); return rc; } /* elase result is in pconn->cm_id->qp */ rc = ibv_query_qp(pconn->cm_id->qp, &attr, IBV_QP_PATH_MTU, &init_attr); if (rc) { sprintf(ibw_lasterr, "ibv_query_qp failed with %d\n", rc); return rc; } return ibw_fill_cq(conn); }
/* called when a listening socket becomes readable. */ static void standard_accept_connection(struct tevent_context *ev, struct loadparm_context *lp_ctx, struct socket_context *sock, void (*new_conn)(struct tevent_context *, struct loadparm_context *, struct socket_context *, struct server_id , void *), void *private_data) { NTSTATUS status; struct socket_context *sock2; pid_t pid; struct socket_address *c, *s; struct standard_child_state *state; struct tevent_fd *fde = NULL; struct tevent_signal *se = NULL; state = setup_standard_child_pipe(ev, NULL); if (state == NULL) { return; } /* accept an incoming connection. */ status = socket_accept(sock, &sock2); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("standard_accept_connection: accept: %s\n", nt_errstr(status))); /* this looks strange, but is correct. We need to throttle things until the system clears enough resources to handle this new socket */ sleep(1); close(state->to_parent_fd); state->to_parent_fd = -1; TALLOC_FREE(state); return; } pid = fork(); if (pid != 0) { close(state->to_parent_fd); state->to_parent_fd = -1; if (pid > 0) { state->pid = pid; } else { TALLOC_FREE(state); } /* parent or error code ... */ talloc_free(sock2); /* go back to the event loop */ return; } /* this leaves state->to_parent_fd open */ TALLOC_FREE(state); pid = getpid(); /* This is now the child code. We need a completely new event_context to work with */ if (tevent_re_initialise(ev) != 0) { smb_panic("Failed to re-initialise tevent after fork"); } /* this will free all the listening sockets and all state that is not associated with this new connection */ talloc_free(sock); /* we don't care if the dup fails, as its only a select() speed optimisation */ socket_dup(sock2); /* tdb needs special fork handling */ ldb_wrap_fork_hook(); /* Must be done after a fork() to reset messaging contexts. */ status = imessaging_reinit_all(); if (!NT_STATUS_IS_OK(status)) { smb_panic("Failed to re-initialise imessaging after fork"); } fde = tevent_add_fd(ev, ev, child_pipe[0], TEVENT_FD_READ, standard_pipe_handler, NULL); if (fde == NULL) { smb_panic("Failed to add fd handler after fork"); } if (child_pipe[1] != -1) { close(child_pipe[1]); child_pipe[1] = -1; } se = tevent_add_signal(ev, ev, SIGHUP, 0, sighup_signal_handler, NULL); if (se == NULL) { smb_panic("Failed to add SIGHUP handler after fork"); } se = tevent_add_signal(ev, ev, SIGTERM, 0, sigterm_signal_handler, NULL); if (se == NULL) { smb_panic("Failed to add SIGTERM handler after fork"); } /* setup the process title */ c = socket_get_peer_addr(sock2, ev); s = socket_get_my_addr(sock2, ev); if (s && c) { setproctitle("conn c[%s:%u] s[%s:%u] server_id[%d]", c->addr, c->port, s->addr, s->port, (int)pid); } talloc_free(c); talloc_free(s); /* setup this new connection. Cluster ID is PID based for this process model */ new_conn(ev, lp_ctx, sock2, cluster_id(pid, 0), private_data); /* we can't return to the top level here, as that event context is gone, so we now process events in the new event context until there are no more to process */ tevent_loop_wait(ev); talloc_free(ev); exit(0); }
int setup_watchdog(struct tevent_context *ev, int interval) { struct sigevent sev; struct itimerspec its; struct tevent_fd *tfd; int signum = SIGRTMIN; int ret; memset(&sev, 0, sizeof(sev)); CatchSignal(signum, watchdog_handler); sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = signum; sev.sigev_value.sival_ptr = &watchdog_ctx.timerid; errno = 0; ret = timer_create(CLOCK_MONOTONIC, &sev, &watchdog_ctx.timerid); if (ret == -1) { ret = errno; DEBUG(SSSDBG_FATAL_FAILURE, "Failed to create watchdog timer (%d) [%s]\n", ret, strerror(ret)); return ret; } if (interval == 0) { interval = WATCHDOG_DEF_INTERVAL; } watchdog_ctx.interval.tv_sec = interval; watchdog_ctx.interval.tv_usec = 0; watchdog_ctx.ev = ev; watchdog_ctx.input_interval = interval; watchdog_ctx.timestamp = time(NULL); ret = pipe(watchdog_ctx.pipefd); if (ret == -1) { ret = errno; DEBUG(SSSDBG_FATAL_FAILURE, "pipe failed [%d] [%s].\n", ret, strerror(ret)); return ret; } sss_fd_nonblocking(watchdog_ctx.pipefd[0]); sss_fd_nonblocking(watchdog_ctx.pipefd[1]); tfd = tevent_add_fd(ev, (TALLOC_CTX *)ev, watchdog_ctx.pipefd[0], TEVENT_FD_READ, watchdog_fd_read_handler, NULL); watchdog_ctx.tfd = tfd; /* Start the timer */ /* we give 1 second head start to the watchdog event */ its.it_value.tv_sec = interval + 1; its.it_value.tv_nsec = 0; its.it_interval.tv_sec = interval; its.it_interval.tv_nsec = 0; errno = 0; ret = timer_settime(watchdog_ctx.timerid, 0, &its, NULL); if (ret == -1) { ret = errno; DEBUG(SSSDBG_FATAL_FAILURE, "Failed to create watchdog timer (%d) [%s]\n", ret, strerror(ret)); return ret; } /* Add the watchdog event and make it fire as fast as the timer */ watchdog_event_handler(ev, NULL, tevent_timeval_zero(), NULL); return EOK; }
/* called to create a new server task */ static void standard_new_task(struct tevent_context *ev, struct loadparm_context *lp_ctx, const char *service_name, void (*new_task)(struct tevent_context *, struct loadparm_context *lp_ctx, struct server_id , void *), void *private_data) { pid_t pid; NTSTATUS status; struct standard_child_state *state; struct tevent_fd *fde = NULL; struct tevent_signal *se = NULL; state = setup_standard_child_pipe(ev, service_name); if (state == NULL) { return; } pid = fork(); if (pid != 0) { close(state->to_parent_fd); state->to_parent_fd = -1; if (pid > 0) { state->pid = pid; } else { TALLOC_FREE(state); } /* parent or error code ... go back to the event loop */ return; } /* this leaves state->to_parent_fd open */ TALLOC_FREE(state); pid = getpid(); /* this will free all the listening sockets and all state that is not associated with this new connection */ if (tevent_re_initialise(ev) != 0) { smb_panic("Failed to re-initialise tevent after fork"); } /* ldb/tdb need special fork handling */ ldb_wrap_fork_hook(); /* Must be done after a fork() to reset messaging contexts. */ status = imessaging_reinit_all(); if (!NT_STATUS_IS_OK(status)) { smb_panic("Failed to re-initialise imessaging after fork"); } fde = tevent_add_fd(ev, ev, child_pipe[0], TEVENT_FD_READ, standard_pipe_handler, NULL); if (fde == NULL) { smb_panic("Failed to add fd handler after fork"); } if (child_pipe[1] != -1) { close(child_pipe[1]); child_pipe[1] = -1; } se = tevent_add_signal(ev, ev, SIGHUP, 0, sighup_signal_handler, NULL); if (se == NULL) { smb_panic("Failed to add SIGHUP handler after fork"); } se = tevent_add_signal(ev, ev, SIGTERM, 0, sigterm_signal_handler, NULL); if (se == NULL) { smb_panic("Failed to add SIGTERM handler after fork"); } setproctitle("task %s server_id[%d]", service_name, (int)pid); /* setup this new task. Cluster ID is PID based for this process model */ new_task(ev, lp_ctx, cluster_id(pid, 0), private_data); /* we can't return to the top level here, as that event context is gone, so we now process events in the new event context until there are no more to process */ tevent_loop_wait(ev); talloc_free(ev); exit(0); }
struct ibw_ctx *ibw_init(struct ibw_initattr *attr, int nattr, void *ctx_userdata, ibw_connstate_fn_t ibw_connstate, ibw_receive_fn_t ibw_receive, struct tevent_context *ectx) { struct ibw_ctx *ctx = talloc_zero(NULL, struct ibw_ctx); struct ibw_ctx_priv *pctx; int rc; DEBUG(DEBUG_DEBUG, ("ibw_init(ctx_userdata: %p, ectx: %p)\n", ctx_userdata, ectx)); /* initialize basic data structures */ memset(ibw_lasterr, 0, IBW_LASTERR_BUFSIZE); assert(ctx!=NULL); ibw_lasterr[0] = '\0'; talloc_set_destructor(ctx, ibw_ctx_destruct); ctx->ctx_userdata = ctx_userdata; pctx = talloc_zero(ctx, struct ibw_ctx_priv); talloc_set_destructor(pctx, ibw_ctx_priv_destruct); ctx->internal = (void *)pctx; assert(pctx!=NULL); pctx->connstate_func = ibw_connstate; pctx->receive_func = ibw_receive; pctx->ectx = ectx; /* process attributes */ if (ibw_process_init_attrs(attr, nattr, &pctx->opts)) goto cleanup; /* init cm */ pctx->cm_channel = rdma_create_event_channel(); if (!pctx->cm_channel) { sprintf(ibw_lasterr, "rdma_create_event_channel error %d\n", errno); goto cleanup; } pctx->cm_channel_event = tevent_add_fd(pctx->ectx, pctx, pctx->cm_channel->fd, TEVENT_FD_READ, ibw_event_handler_cm, ctx); #if RDMA_USER_CM_MAX_ABI_VERSION >= 2 rc = rdma_create_id(pctx->cm_channel, &pctx->cm_id, ctx, RDMA_PS_TCP); #else rc = rdma_create_id(pctx->cm_channel, &pctx->cm_id, ctx); #endif if (rc) { rc = errno; sprintf(ibw_lasterr, "rdma_create_id error %d\n", rc); goto cleanup; } DEBUG(DEBUG_DEBUG, ("created cm_id %p\n", pctx->cm_id)); pctx->pagesize = sysconf(_SC_PAGESIZE); return ctx; /* don't put code here */ cleanup: DEBUG(DEBUG_ERR, (ibw_lasterr)); if (ctx) talloc_free(ctx); return NULL; }
static struct standard_child_state *setup_standard_child_pipe(struct tevent_context *ev, const char *name) { struct standard_child_state *state; int parent_child_pipe[2]; int ret; /* * Prepare a pipe to allow us to know when the child exits, * because it will trigger a read event on this private * pipe. * * We do all this before the accept and fork(), so we can * clean up if it fails. */ state = talloc_zero(ev, struct standard_child_state); if (state == NULL) { return NULL; } if (name == NULL) { name = ""; } state->name = talloc_strdup(state, name); if (state->name == NULL) { TALLOC_FREE(state); return NULL; } ret = pipe(parent_child_pipe); if (ret == -1) { DEBUG(0, ("Failed to create parent-child pipe to handle " "SIGCHLD to track new process for socket\n")); TALLOC_FREE(state); return NULL; } smb_set_close_on_exec(parent_child_pipe[0]); smb_set_close_on_exec(parent_child_pipe[1]); state->from_child_fd = parent_child_pipe[0]; state->to_parent_fd = parent_child_pipe[1]; /* * The basic purpose of calling this handler is to ensure we * call waitpid() and so avoid zombies (now that we no longer * user SIGIGN on for SIGCHLD), but it also allows us to clean * up other resources in the future. */ state->from_child_fde = tevent_add_fd(ev, state, state->from_child_fd, TEVENT_FD_READ, standard_child_pipe_handler, state); if (state->from_child_fde == NULL) { TALLOC_FREE(state); return NULL; } tevent_fd_set_auto_close(state->from_child_fde); return state; }