X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fserver_main.c;h=592ea7708bbc620f518e10eb21af59406b86642d;hb=a793d2fbf5e0aa9151490b76defd22f6db7ef7ed;hp=94ee493ff340281bdbe39fb0dbd658e922205a20;hpb=4050134067b948953758b2bad2702211e1dd46fd;p=citadel.git diff --git a/citadel/server_main.c b/citadel/server_main.c index 94ee493ff..592ea7708 100644 --- a/citadel/server_main.c +++ b/citadel/server_main.c @@ -1,7 +1,15 @@ /* * citserver's main() function lives here. + * + * Copyright (c) 1987-2012 by the citadel.org team * - * $Id$ + * This program is open source software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include "sysdep.h" @@ -37,19 +45,30 @@ #include #include #include -#ifdef HAVE_PTHREAD_H -#include +#include +#ifdef HAVE_SYS_PRCTL_H +#include #endif +#include #include "citadel.h" #include "server.h" #include "serv_extensions.h" #include "sysdep_decls.h" +#include "threads.h" #include "citserver.h" #include "support.h" #include "config.h" +#include "control.h" #include "database.h" +#include "user_ops.h" #include "housekeeping.h" -#include "tools.h" +#include "svn_revision.h" +#include "citadel_dirs.h" + +#include "context.h" + +#include "modules_init.h" +#include "ecrash.h" #ifdef HAVE_SYS_SELECT_H #include @@ -58,116 +77,216 @@ #ifndef HAVE_SNPRINTF #include "snprintf.h" #endif +const char *CitadelServiceUDS="citadel-UDS"; +const char *CitadelServiceTCP="citadel-TCP"; + + + +void go_threading(void); /* * Here's where it all begins. */ int main(int argc, char **argv) { - char tracefile[128]; /* Name of file to log traces to */ - int a, i; /* General-purpose variables */ - struct passwd *pw; + char facility[32]; + int a; /* General-purpose variables */ + struct passwd pw, *pwp = NULL; + char pwbuf[SIZ]; int drop_root_perms = 1; - struct worker_node *wnp; - size_t size; - - /* specify default port name and trace file */ - strcpy(tracefile, ""); + int relh=0; + int home=0; + int dbg=0; + char relhome[PATH_MAX]=""; + char ctdldir[PATH_MAX]=CTDLDIR; + int syslog_facility = LOG_DAEMON; +#ifdef HAVE_RUN_DIR + struct stat filestats; +#endif +#ifdef HAVE_BACKTRACE + eCrashParameters params; +// eCrashSymbolTable symbol_table; +#endif /* initialize the master context */ InitializeMasterCC(); + InitializeMasterTSD(); /* parse command-line arguments */ for (a=1; a= 0) { - openlog("citadel", LOG_PID, syslog_facility); - } + if (!strncmp(argv[a], "-l", 2)) { + safestrncpy(facility, &argv[a][2], sizeof(facility)); + syslog_facility = SyslogFacility(facility); } /* run in the background if -d was specified */ else if (!strcmp(argv[a], "-d")) { - start_daemon( (strlen(tracefile) > 0) ? 0 : 1 ) ; + running_as_daemon = 1; + } + + else if (!strncmp(argv[a], "-h", 2)) { + relh=argv[a][2]!='/'; + if (!relh) { + safestrncpy(ctdl_home_directory, &argv[a][2], sizeof ctdl_home_directory); + } + else { + safestrncpy(relhome, &argv[a][2], sizeof relhome); + } + home=1; } - /* -x specifies the desired logging level */ else if (!strncmp(argv[a], "-x", 2)) { - verbosity = atoi(&argv[a][2]); + /* deprecated */ } - else if (!strncmp(argv[a], "-h", 2)) { - safestrncpy(bbs_home_directory, &argv[a][2], - sizeof bbs_home_directory); - home_specified = 1; + else if (!strncmp(argv[a], "-t", 2)) { + /* deprecated */ } - else if (!strncmp(argv[a], "-f", 2)) { - do_defrag = 1; + else if (!strncmp(argv[a], "-D", 2)) { + dbg = 1; } /* -r tells the server not to drop root permissions. don't use * this unless you know what you're doing. this should be * removed in the next release if it proves unnecessary. */ - else if (!strcmp(argv[a], "-r")) + else if (!strcmp(argv[a], "-r")) { drop_root_perms = 0; + } /* any other parameter makes it crash and burn */ else { - lprintf(1, "citserver: usage: " - "citserver [-tTraceFile] " + fprintf(stderr, "citserver: usage: " + "citserver " "[-lLogFacility] " - "[-d] [-f]" - " [-xLogLevel] [-hHomeDir]\n"); + "[-d] [-D] [-s] " + "[-hHomeDir]\n" + ); exit(1); } } - /* Tell 'em who's in da house */ - lprintf(1, - "\n\n*** Citadel/UX messaging server engine v%d.%02d ***\n" - "Copyright (C) 1987-2003 by the Citadel/UX development team.\n" - "This program is distributed under the terms of the GNU " - "General Public License.\n\n", - (REV_LEVEL/100), - (REV_LEVEL%100) + openlog("citserver", + ( running_as_daemon ? (LOG_PID) : (LOG_PID | LOG_PERROR) ), + syslog_facility ); - /* Initialize... */ - init_sysdep(); + calc_dirs_n_files(relh, home, relhome, ctdldir, dbg); + /* daemonize, if we were asked to */ + if (running_as_daemon) { + start_daemon(0); + drop_root_perms = 1; + } + +#ifdef HAVE_BACKTRACE + bzero(¶ms, sizeof(params)); + params.filename = file_pid_paniclog; + panic_fd=open(file_pid_paniclog, O_APPEND|O_CREAT|O_DIRECT); + params.filep = fopen(file_pid_paniclog, "a+"); + params.debugLevel = ECRASH_DEBUG_VERBOSE; + params.dumpAllThreads = TRUE; + params.useBacktraceSymbols = 1; + params.signals[0]=SIGSEGV; + params.signals[1]=SIGILL; + params.signals[2]=SIGBUS; + params.signals[3]=SIGABRT; + eCrash_Init(¶ms); + eCrash_RegisterThread("MasterThread", 0); +#endif + + /* Tell 'em who's in da house */ + syslog(LOG_NOTICE, " "); + syslog(LOG_NOTICE, " "); + syslog(LOG_NOTICE, + "*** Citadel server engine v%d.%02d (build %s) ***", + (REV_LEVEL/100), (REV_LEVEL%100), svn_revision()); + syslog(LOG_NOTICE, "Copyright (C) 1987-2012 by the Citadel development team."); + syslog(LOG_NOTICE, "This program is distributed under the terms of the GNU " + "General Public License."); + syslog(LOG_NOTICE, " "); + syslog(LOG_DEBUG, "Called as: %s", argv[0]); + syslog(LOG_INFO, "%s", libcitadel_version_string()); /* Load site-specific parameters, and set the ipgm secret */ - lprintf(7, "Loading citadel.config\n"); + syslog(LOG_INFO, "Loading citadel.config"); get_config(); config.c_ipgm_secret = rand(); + + /* get_control() MUST MUST MUST be called BEFORE the databases are opened!! */ + syslog(LOG_INFO, "Acquiring control record"); + get_control(); + put_config(); +#ifdef HAVE_RUN_DIR + /* on some dists rundir gets purged on startup. so we need to recreate it. */ + + if (stat(ctdl_run_dir, &filestats)==-1){ +#ifdef HAVE_GETPWUID_R +#ifdef SOLARIS_GETPWUID + pwp = getpwuid_r(config.c_ctdluid, &pw, pwbuf, sizeof(pwbuf)); +#else // SOLARIS_GETPWUID + getpwuid_r(config.c_ctdluid, &pw, pwbuf, sizeof(pwbuf), &pwp); +#endif // SOLARIS_GETPWUID +#else // HAVE_GETPWUID_R + pwp = NULL; +#endif // HAVE_GETPWUID_R + + if ((mkdir(ctdl_run_dir, 0755) != 0) && (errno != EEXIST)) + syslog(LOG_EMERG, + "unable to create run directory [%s]: %s", + ctdl_run_dir, strerror(errno)); + + if (chown(ctdl_run_dir, config.c_ctdluid, (pwp==NULL)?-1:pw.pw_gid) != 0) + syslog(LOG_EMERG, + "unable to set the access rights for [%s]: %s", + ctdl_run_dir, strerror(errno)); + } + + +#endif + + /* Initialize... */ + init_sysdep(); + /* * Do non system dependent startup functions. */ master_startup(); + /* + * Check that the control record is correct and place sensible values if it isn't + */ + check_control(); + + /* + * Run any upgrade entry points + */ + syslog(LOG_INFO, "Upgrading modules."); + upgrade_modules(); + +/* + * Load the user for the masterCC or create them if they don't exist + */ + if (CtdlGetUser(&masterCC.user, "SYS_Citadel")) + { + /* User doesn't exist. We can't use create user here as the user number needs to be 0 */ + strcpy (masterCC.user.fullname, "SYS_Citadel") ; + CtdlPutUser(&masterCC.user); + CtdlGetUser(&masterCC.user, "SYS_Citadel"); /* Just to be safe */ + } + /* * Bind the server to a Unix-domain socket. */ CtdlRegisterServiceHook(0, - "citadel.socket", + file_citadel_socket, citproto_begin_session, - do_command_loop); + do_command_loop, + do_async_loop, + CitadelServiceUDS); /* * Bind the server to our favorite TCP port (usually 504). @@ -175,84 +294,76 @@ int main(int argc, char **argv) CtdlRegisterServiceHook(config.c_port_number, NULL, citproto_begin_session, - do_command_loop); + do_command_loop, + do_async_loop, + CitadelServiceTCP); + + + /* * Load any server-side extensions available here. */ - lprintf(7, "Initializing server extensions\n"); - size = strlen(bbs_home_directory) + 9; - initialize_server_extensions(); + syslog(LOG_INFO, "Initializing server extensions"); + + initialise_modules(0); /* - * The rescan pipe exists so that worker threads can be woken up and - * told to re-scan the context list for fd's to listen on. This is - * necessary, for example, when a context is about to go idle and needs - * to get back on that list. + * If we need host auth, start our chkpwd daemon. */ - if (pipe(rescan)) { - lprintf(1, "Can't create rescan pipe!\n"); - exit(errno); + if (config.c_auth_mode == AUTHMODE_HOST) { + start_chkpwd_daemon(); } - init_master_fdset(); /* - * Now that we've bound the sockets, change to the BBS user id and its + * check, whether we're fired up another time after a crash. + * if, post an aide message, so the admin has a chance to react. + */ + checkcrash (); + + + /* + * Now that we've bound the sockets, change to the Citadel user id and its * corresponding group ids */ if (drop_root_perms) { - if ((pw = getpwuid(BBSUID)) == NULL) - lprintf(1, "WARNING: getpwuid(%ld): %s\n" - "Group IDs will be incorrect.\n", (long)BBSUID, + cdb_chmod_data(); /* make sure we own our data files */ + +#ifdef HAVE_GETPWUID_R +#ifdef SOLARIS_GETPWUID + pwp = getpwuid_r(config.c_ctdluid, &pw, pwbuf, sizeof(pwbuf)); +#else // SOLARIS_GETPWUID + getpwuid_r(config.c_ctdluid, &pw, pwbuf, sizeof(pwbuf), &pwp); +#endif // SOLARIS_GETPWUID +#else // HAVE_GETPWUID_R + pwp = NULL; +#endif // HAVE_GETPWUID_R + + if (pwp == NULL) + syslog(LOG_CRIT, "WARNING: getpwuid(%ld): %s" + "Group IDs will be incorrect.\n", (long)CTDLUID, strerror(errno)); else { - initgroups(pw->pw_name, pw->pw_gid); - if (setgid(pw->pw_gid)) - lprintf(3, "setgid(%ld): %s\n", (long)pw->pw_gid, + initgroups(pw.pw_name, pw.pw_gid); + if (setgid(pw.pw_gid)) + syslog(LOG_CRIT, "setgid(%ld): %s", (long)pw.pw_gid, strerror(errno)); } - lprintf(7, "Changing uid to %ld\n", (long)BBSUID); - if (setuid(BBSUID) != 0) { - lprintf(3, "setuid() failed: %s\n", strerror(errno)); + syslog(LOG_INFO, "Changing uid to %ld", (long)CTDLUID); + if (setuid(CTDLUID) != 0) { + syslog(LOG_CRIT, "setuid() failed: %s", strerror(errno)); } +#if defined (HAVE_SYS_PRCTL_H) && defined (PR_SET_DUMPABLE) + prctl(PR_SET_DUMPABLE, 1); +#endif } /* We want to check for idle sessions once per minute */ CtdlRegisterSessionHook(terminate_idle_sessions, EVT_TIMER); - /* - * Now create a bunch of worker threads. - */ - lprintf(9, "Starting %d worker threads\n", config.c_min_workers-1); - begin_critical_section(S_WORKER_LIST); - for (i=0; i<(config.c_min_workers-1); ++i) { - create_worker(); - } - end_critical_section(S_WORKER_LIST); - - /* Now this thread can become a worker as well. */ - initial_thread = pthread_self(); - worker_thread(NULL); - - /* Server is exiting. Wait for workers to shutdown. */ - lprintf(7, "Waiting for worker threads to shut down\n"); - - begin_critical_section(S_WORKER_LIST); - while (worker_list != NULL) { - wnp = worker_list; - worker_list = wnp->next; - - /* avoid deadlock with an exiting thread */ - end_critical_section(S_WORKER_LIST); - if ((i = pthread_join(wnp->tid, NULL))) - lprintf(1, "pthread_join: %s\n", strerror(i)); - phree(wnp); - begin_critical_section(S_WORKER_LIST); - } - end_critical_section(S_WORKER_LIST); - - master_cleanup(); - + go_threading(); + + master_cleanup(exit_signal); return(0); }