X-Git-Url: http://git.samba.org/samba.git/?p=ira%2Fwip.git;a=blobdiff_plain;f=source4%2Fsmbd%2Fserver.c;h=dd63ca1ecabd5901a514bed36aba67eb986624d0;hp=e7487951775b4c4cc89222c16983a91cfb736676;hb=774fa12ac1695600710ce9fac18024edd38161ee;hpb=45a85bdd353418828df8017a9d7eb7c14f6f0cd3 diff --git a/source4/smbd/server.c b/source4/smbd/server.c index e7487951775..dd63ca1ecab 100644 --- a/source4/smbd/server.c +++ b/source4/smbd/server.c @@ -1,14 +1,16 @@ /* Unix SMB/CIFS implementation. + Main SMB server routines - Copyright (C) Andrew Tridgell 1992-1998 + + Copyright (C) Andrew Tridgell 1992-2005 Copyright (C) Martin Pool 2002 Copyright (C) Jelmer Vernooij 2002 Copyright (C) James J Myers 2003 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -17,144 +19,338 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + along with this program. If not, see . */ #include "includes.h" +#include "lib/events/events.h" +#include "version.h" +#include "lib/cmdline/popt_common.h" +#include "system/dir.h" +#include "system/filesys.h" +#include "build.h" +#include "ldb/include/ldb.h" +#include "registry/registry.h" +#include "ntvfs/ntvfs.h" +#include "ntptr/ntptr.h" +#include "auth/gensec/gensec.h" +#include "smbd/process_model.h" +#include "smbd/service.h" +#include "param/secrets.h" +#include "smbd/pidfile.h" +#include "cluster/ctdb/ctdb_cluster.h" +#include "param/param.h" -static void exit_server(const char *reason) +/* + recursively delete a directory tree +*/ +static void recursive_delete(const char *path) { - DEBUG(3,("Server exit (%s)\n", (reason ? reason : ""))); - exit(0); -} + DIR *dir; + struct dirent *de; -/**************************************************************************** - main server. -****************************************************************************/ -static int binary_smbd_main(int argc,const char *argv[]) -{ - BOOL is_daemon = False; - BOOL interactive = False; - BOOL Fork = True; - BOOL log_stdout = False; - int opt; - poptContext pc; - struct server_context *srv_ctx; - const char *model = "standard"; - struct poptOption long_options[] = { - POPT_AUTOHELP - {"daemon", 'D', POPT_ARG_VAL, &is_daemon, True, "Become a daemon (default)" }, - {"interactive", 'i', POPT_ARG_VAL, &interactive, True, "Run interactive (not a daemon)"}, - {"foreground", 'F', POPT_ARG_VAL, &Fork, False, "Run daemon in foreground (for daemontools & etc)" }, - {"log-stdout", 'S', POPT_ARG_VAL, &log_stdout, True, "Log to stdout" }, - {"port", 'p', POPT_ARG_STRING, NULL, 0, "Listen on the specified ports"}, - {"model", 'M', POPT_ARG_STRING, &model, 0, "select process model"}, - POPT_COMMON_SAMBA - { NULL } - }; - - pc = poptGetContext("smbd", argc, argv, long_options, 0); - - while((opt = poptGetNextOpt(pc)) != -1) { - switch (opt) { - case 'p': - lp_set_cmdline("smb ports", poptGetOptArg(pc)); - break; - } + dir = opendir(path); + if (!dir) { + return; } - poptFreeContext(pc); - load_case_tables(); + for (de=readdir(dir);de;de=readdir(dir)) { + char *fname; + struct stat st; - if (interactive) { - Fork = False; - log_stdout = True; + if (ISDOT(de->d_name) || ISDOTDOT(de->d_name)) { + continue; + } + + fname = talloc_asprintf(path, "%s/%s", path, de->d_name); + if (stat(fname, &st) != 0) { + continue; + } + if (S_ISDIR(st.st_mode)) { + recursive_delete(fname); + talloc_free(fname); + continue; + } + if (unlink(fname) != 0) { + DEBUG(0,("Unabled to delete '%s' - %s\n", + fname, strerror(errno))); + smb_panic("unable to cleanup tmp files"); + } + talloc_free(fname); } + closedir(dir); +} - 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); +/* + cleanup temporary files. This is the new alternative to + TDB_CLEAR_IF_FIRST. Unfortunately TDB_CLEAR_IF_FIRST is not + efficient on unix systems due to the lack of scaling of the byte + range locking system. So instead of putting the burden on tdb to + cleanup tmp files, this function deletes them. +*/ +static void cleanup_tmp_files(struct loadparm_context *lp_ctx) +{ + char *path; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + + path = smbd_tmp_path(mem_ctx, lp_ctx, NULL); + + recursive_delete(path); + talloc_free(mem_ctx); +} + +static void sig_hup(int sig) +{ + debug_schedule_reopen_logs(); +} + +static void sig_term(int sig) +{ +#if HAVE_GETPGRP + static int done_sigterm; + if (done_sigterm == 0 && getpgrp() == getpid()) { + DEBUG(0,("SIGTERM: killing children\n")); + done_sigterm = 1; + kill(-getpgrp(), SIGTERM); } - setup_logging(argv[0], log_stdout?DEBUG_STDOUT:DEBUG_FILE); +#endif + exit(0); +} - fault_setup((void (*)(void *))exit_server); - +/* + setup signal masks +*/ +static void setup_signals(void) +{ /* we are never interested in SIGPIPE */ - BlockSignals(True,SIGPIPE); + BlockSignals(true,SIGPIPE); #if defined(SIGFPE) /* we are never interested in SIGFPE */ - BlockSignals(True,SIGFPE); + BlockSignals(true,SIGFPE); #endif + /* We are no longer interested in USR1 */ + BlockSignals(true, SIGUSR1); + #if defined(SIGUSR2) /* We are no longer interested in USR2 */ - BlockSignals(True,SIGUSR2); + 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); + BlockSignals(false, SIGHUP); + BlockSignals(false, SIGTERM); + + CatchSignal(SIGHUP, sig_hup); + CatchSignal(SIGTERM, sig_term); +} + +/* + handle io on stdin +*/ +static void server_stdin_handler(struct event_context *event_ctx, struct fd_event *fde, + uint16_t flags, void *private) +{ + const char *binary_name = (const char *)private; + uint8_t c; + if (read(0, &c, 1) == 0) { + DEBUG(0,("%s: EOF on stdin - terminating\n", binary_name)); +#if HAVE_GETPGRP + if (getpgrp() == getpid()) { + kill(-getpgrp(), SIGTERM); + } +#endif + exit(0); + } +} + +/* + die if the user selected maximum runtime is exceeded +*/ +_NORETURN_ static void max_runtime_handler(struct event_context *ev, + struct timed_event *te, + struct timeval t, void *private) +{ + const char *binary_name = (const char *)private; + DEBUG(0,("%s: maximum runtime exceeded - terminating\n", binary_name)); + exit(0); +} + +/* + 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; + init_module_fn static_init[] = { STATIC_service_MODULES }; + init_module_fn *shared_init; + struct event_context *event_ctx; + NTSTATUS status; + const char *model = "standard"; + int max_runtime = 0; + enum { + OPT_DAEMON = 1000, + OPT_INTERACTIVE, + OPT_PROCESS_MODEL + }; + 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"}, + 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; + default: + fprintf(stderr, "\nInvalid option %s: %s\n\n", + poptBadOption(pc, 0), poptStrerror(opt)); + poptPrintUsage(pc, stderr, 0); + exit(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); + exit(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); - reopen_logs(); - - DEBUG(0,("smbd version %s started.\n", SAMBA_VERSION_STRING)); - DEBUGADD(0,("Copyright Andrew Tridgell and the Samba Team 1992-2004\n")); + DEBUG(0,("%s version %s started.\n", binary_name, SAMBA_VERSION_STRING)); + DEBUGADD(0,("Copyright Andrew Tridgell and the Samba Team 1992-2007\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))); exit(1); } - if (!reload_services(NULL, False)) - return(-1); - - if (!is_daemon && !is_a_socket(0)) { - if (!interactive) - DEBUG(0,("standard input is not a socket, assuming -D option\n")); + if (opt_daemon) { + DEBUG(3,("Becoming a daemon.\n")); + become_daemon(true); + } - /* - * Setting is_daemon here prevents us from eventually calling - * the open_sockets_inetd() - */ + cleanup_tmp_files(cmdline_lp_ctx); - is_daemon = True; + if (!directory_exist(lp_lockdir(cmdline_lp_ctx))) { + mkdir(lp_lockdir(cmdline_lp_ctx), 0755); } - if (is_daemon && !interactive) { - DEBUG(3,("Becoming a daemon.\n")); - become_daemon(Fork); + pidfile_create(lp_piddir(cmdline_lp_ctx), binary_name); + + /* Do *not* remove this, until you have removed + * passdb/secrets.c, and proved that Samba still builds... */ + /* Setup the SECRETS subsystem */ + if (!secrets_init(cmdline_lp_ctx)) { + exit(1); } - if (!directory_exist(lp_lockdir(), NULL)) { - mkdir(lp_lockdir(), 0755); + share_init(); + + gensec_init(cmdline_lp_ctx); /* FIXME: */ + + ntptr_init(cmdline_lp_ctx); /* 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, cmdline_lp_ctx, "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 = event_context_init(talloc_autofree_context()); + + if (event_ctx == NULL) { + DEBUG(0,("Initializing event context failed\n")); + return 1; } - if (is_daemon) { - pidfile_create("smbd"); + /* initialise clustering if needed */ + cluster_ctdb_init(cmdline_lp_ctx, event_ctx, model); + + if (opt_interactive) { + /* catch EOF on stdin */ +#ifdef SIGTTIN + signal(SIGTTIN, SIG_IGN); +#endif + event_add_fd(event_ctx, event_ctx, 0, EVENT_FD_READ, + server_stdin_handler, + discard_const(binary_name)); } - init_subsystems(); - DEBUG(0,("Using %s process model\n", model)); - srv_ctx = server_service_startup(model); - if (!srv_ctx) { - DEBUG(0,("Starting Services failed.\n")); + if (max_runtime) { + event_add_timed(event_ctx, event_ctx, + timeval_current_ofs(max_runtime, 0), + max_runtime_handler, + discard_const(binary_name)); + } + + DEBUG(0,("%s: using '%s' process model\n", binary_name, model)); + status = server_service_startup(event_ctx, cmdline_lp_ctx, model, + lp_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 */ - return event_loop_wait(srv_ctx->events); + /* wait for events - this is where smbd sits for most of its + life */ + event_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[]) { - return binary_smbd_main(argc, argv); + return binary_smbd_main("smbd", argc, argv); }