diff --git a/include/econfig-spec.h b/include/econfig-spec.h index c19e5c26..3983ad31 100644 --- a/include/econfig-spec.h +++ b/include/econfig-spec.h @@ -88,6 +88,8 @@ EMPCFBOTH("listen_addr", listen_addr, char *, NSC_STRING, KM_INTERNAL, EMPCF_COMMENT("# \"\" listens on all, localhost just on the loopback interface") EMPCFBOTH("port", loginport, char *, NSC_STRING, KM_INTERNAL, "TCP port the server will bind") +EMPCFBOTH("keep_journal", keep_journal, int, NSC_INT, KM_INTERNAL, + "Enable journal log file") EMPCFBOTH("privname", privname, char *, NSC_STRING, 0, "Name of the deity") EMPCFBOTH("privlog", privlog, char *, NSC_STRING, 0, diff --git a/include/empthread.h b/include/empthread.h index 172e89a0..00d6a054 100644 --- a/include/empthread.h +++ b/include/empthread.h @@ -188,10 +188,9 @@ void empth_wakeup(empth_t *thread); void empth_sleep(time_t until); /* - * Wait for some implementation-defined external shutdown signal. - * Return a non-negative number identifying the signal. + * Wait for signal, return the signal number */ -int empth_wait_for_shutdown(void); +int empth_wait_for_signal(void); /* * Create a semaphore. diff --git a/include/journal.h b/include/journal.h new file mode 100644 index 00000000..61d4170d --- /dev/null +++ b/include/journal.h @@ -0,0 +1,48 @@ +/* + * Empire - A multi-player, client/server Internet based war game. + * Copyright (C) 1986-2006, Dave Pare, Jeff Bailey, Thomas Ruschak, + * Ken Stevens, Steve McClure + * + * 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 + * (at your option) any later version. + * + * 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. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * --- + * + * See files README, COPYING and CREDITS in the root of the source + * tree for related information and legal notices. It is expected + * that future projects/authors will amend these files as needed. + * + * --- + * + * journal.h: Log a journal of events to a file + * + * Known contributors to this file: + * Markus Armbruster, 2004-2006 + */ + +#ifndef JOURNAL_H +#define JOURNAL_H + +int journal_open(void); +int journal_close(void); +void journal_entry(char *fmt, ...); + +int journal_startup(void); +void journal_shutdown(void); +void journal_login(void); +void journal_logout(void); +void journal_input(char *input); +void journal_update(int); + +#endif diff --git a/src/lib/common/journal.c b/src/lib/common/journal.c new file mode 100644 index 00000000..31124de9 --- /dev/null +++ b/src/lib/common/journal.c @@ -0,0 +1,151 @@ +/* + * Empire - A multi-player, client/server Internet based war game. + * Copyright (C) 1986-2000, Dave Pare, Jeff Bailey, Thomas Ruschak, + * Ken Stevens, Steve McClure + * + * 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 + * (at your option) any later version. + * + * 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. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * --- + * + * See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the + * related information and legal notices. It is expected that any future + * projects/authors will amend these files as needed. + * + * --- + * + * journal.c: Log a journal of events to a file + * + * Known contributors to this file: + * Markus Armbruster, 2004-2006 + */ + +/* + * Journal file format: each line logs an event, and looks like this: + * + * TIME THREAD EVENT DATA + * + * Events and their data are: + * + * startup + * shutdown + * login CNUM HOSTADDR USER + * logout CNUM + * input INPUT + * update ETU + */ + +#include + +#include +#include +#include +#include +#include +#include +#include "misc.h" +#include "empthread.h" +#include "journal.h" +#include "optlist.h" +#include "player.h" +#include "prototypes.h" + +static char journal_fname[] = "journal.log"; +static FILE *journal; + +int +journal_open(void) +{ + journal = fopen(journal_fname, "a+"); + return journal ? 0 : -1; +} + +int +journal_close(void) +{ + FILE *j = journal; + journal = NULL; + return j ? fclose(j) : 0; +} + +void +journal_entry(char *fmt, ...) +{ + static char buf[1024]; + va_list ap; + time_t now; + int n, i, olderr; + + if (journal) { + time(&now); + n = sprintf(buf, "%.24s %p ", ctime(&now), empth_self()); + va_start(ap, fmt); + vsnprintf(buf + n, sizeof(buf) - n - 1, fmt, ap); + va_end(ap); + + for (i = n; buf[i]; ++i) { + if (!isprint(buf[i])) + buf[i] = '?'; /* FIXME replace by escape */ + } + buf[i++] = '\n'; + buf[i] = 0; + if (fputs(buf, journal) == EOF) + logerror("Error writing journal (%s)", strerror(errno)); + } +} + +int +journal_startup(void) +{ + if (!keep_journal) + return 0; + if (journal_open() < 0) { + logerror("Can't open %s (%s)", journal_fname, strerror(errno)); + return -1; + } + journal_entry("startup"); + return 0; +} + +void +journal_shutdown(void) +{ + journal_entry("shutdown"); + journal_close(); +} + +void +journal_login(void) +{ + journal_entry("login %d %s %s", + player->cnum, player->hostaddr, player->userid); +} + +void +journal_logout(void) +{ + journal_entry("logout %d", player->cnum); +} + +void +journal_input(char *input) +{ + journal_entry("input %s", input); +} + +void +journal_update(int etu) +{ + journal_entry("update %d", etu); +} diff --git a/src/lib/empthread/lwp.c b/src/lib/empthread/lwp.c index 4643583f..2d873649 100644 --- a/src/lib/empthread/lwp.c +++ b/src/lib/empthread/lwp.c @@ -49,6 +49,7 @@ empth_init(void **ctx, int flags) empth_flags = flags; empth_init_signals(); sigemptyset(&set); + sigaddset(&set, SIGHUP); sigaddset(&set, SIGINT); sigaddset(&set, SIGTERM); lwpInitSystem(PP_MAIN, ctx, flags, &set); @@ -108,13 +109,14 @@ empth_sleep(time_t until) } int -empth_wait_for_shutdown(void) +empth_wait_for_signal(void) { sigset_t set; int sig, err; time_t now; sigemptyset(&set); + sigaddset(&set, SIGHUP); sigaddset(&set, SIGINT); sigaddset(&set, SIGTERM); for (;;) { diff --git a/src/lib/empthread/ntthread.c b/src/lib/empthread/ntthread.c index 3942cbe6..b8228f06 100644 --- a/src/lib/empthread/ntthread.c +++ b/src/lib/empthread/ntthread.c @@ -577,7 +577,7 @@ empth_sleep(time_t until) /************************ * empth_request_shutdown * - * This wakes up empth_wait_for_shutdown() so shutdown can proceed. + * This wakes up empth_wait_for_signal() so shutdown can proceed. * This is done by signalling hShutdownEvent. */ void @@ -587,7 +587,7 @@ empth_request_shutdown(void) } int -empth_wait_for_shutdown(void) +empth_wait_for_signal(void) { /* Get the MUTEX semaphore, wait the number of MS */ WaitForSingleObject(hShutdownEvent, INFINITE); diff --git a/src/lib/empthread/pthread.c b/src/lib/empthread/pthread.c index 6cf2ffa3..4ada7f01 100644 --- a/src/lib/empthread/pthread.c +++ b/src/lib/empthread/pthread.c @@ -152,6 +152,7 @@ empth_init(void **ctx_ptr, int flags) empth_init_signals(); sigemptyset(&set); + sigaddset(&set, SIGHUP); sigaddset(&set, SIGINT); sigaddset(&set, SIGTERM); pthread_sigmask(SIG_BLOCK, &set, NULL); @@ -379,12 +380,13 @@ empth_sleep(time_t until) } int -empth_wait_for_shutdown(void) +empth_wait_for_signal(void) { sigset_t set; int sig, err; sigemptyset(&set); + sigaddset(&set, SIGHUP); sigaddset(&set, SIGINT); sigaddset(&set, SIGTERM); pthread_mutex_unlock(&mtx_ctxsw); diff --git a/src/lib/global/constants.c b/src/lib/global/constants.c index 4effdd64..b911aaf5 100644 --- a/src/lib/global/constants.c +++ b/src/lib/global/constants.c @@ -43,6 +43,8 @@ char *privlog = "careless@invalid"; /* Divine hosts and networks */ char *privip = "127.0.0.1 ::1 ::ffff:127.0.0.1"; +int keep_journal = 0; + int WORLD_X = 64; /* World size - x */ int WORLD_Y = 32; /* World size - y */ diff --git a/src/lib/player/player.c b/src/lib/player/player.c index db7ce5a2..b3d4310a 100644 --- a/src/lib/player/player.c +++ b/src/lib/player/player.c @@ -50,6 +50,7 @@ #include "subs.h" #include "common.h" #include "optlist.h" +#include "journal.h" #if !defined(_WIN32) #include @@ -75,6 +76,7 @@ player_main(struct player *p) player = p; time(&player->lasttime); time(&player->curup); + journal_login(); show_motd(); if (init_nats() < 0) { pr("Server confused, try again later\n"); @@ -138,6 +140,7 @@ player_main(struct player *p) natp->nat_minused += 1; putnat(natp); pr("Bye-bye\n"); + journal_logout(); } static int diff --git a/src/lib/player/recvclient.c b/src/lib/player/recvclient.c index 9a415da3..a6c1d154 100644 --- a/src/lib/player/recvclient.c +++ b/src/lib/player/recvclient.c @@ -37,6 +37,7 @@ #include #include "misc.h" #include "empio.h" +#include "journal.h" #include "player.h" #include "empthread.h" @@ -80,5 +81,6 @@ recvclient(char *cmd, int size) } if (player->aborted) return -2; + journal_input(cmd); return count; } diff --git a/src/lib/subs/fileinit.c b/src/lib/subs/fileinit.c index d6242160..e7c3d797 100644 --- a/src/lib/subs/fileinit.c +++ b/src/lib/subs/fileinit.c @@ -34,6 +34,7 @@ #include #include "file.h" +#include "journal.h" #include "prototypes.h" struct fileinit { @@ -98,6 +99,8 @@ static void ef_open_srv(void) { int failed = 0; + + failed |= journal_startup() < 0; failed |= !ef_open(EF_NATION, EFF_MEM); failed |= !ef_open(EF_SECTOR, EFF_MEM); failed |= !ef_open(EF_SHIP, EFF_MEM); @@ -142,6 +145,7 @@ ef_close_srv(void) ef_close(EF_BMAP); ef_close(EF_LOST); ef_close(EF_REALM); + journal_shutdown(); } static int diff --git a/src/lib/update/main.c b/src/lib/update/main.c index c1d133b9..ea1354d7 100644 --- a/src/lib/update/main.c +++ b/src/lib/update/main.c @@ -46,6 +46,7 @@ #include "update.h" #include "common.h" #include "optlist.h" +#include "journal.h" #include "server.h" #include #if !defined(_WIN32) @@ -92,6 +93,7 @@ update_main(void *unused) * happiness, and printing out the state of the nation) */ logerror("production update (%d etus)", etu); + journal_update(etu); memset(pops, 0, sizeof(pops)); memset(air_money, 0, sizeof(air_money)); memset(sea_money, 0, sizeof(sea_money)); diff --git a/src/server/main.c b/src/server/main.c index 56bd3517..525061c8 100644 --- a/src/server/main.c +++ b/src/server/main.c @@ -41,6 +41,7 @@ #include #endif #include +#include #include #include @@ -57,6 +58,7 @@ #include "misc.h" #include "nat.h" #include "file.h" +#include "journal.h" #include "player.h" #include "empthread.h" #include "plane.h" @@ -119,7 +121,7 @@ main(int argc, char **argv) int remove_service_set = 0; #endif char *config_file = NULL; - int op; + int op, sig; #ifdef _WIN32 # define XOPTS "iI:rR:" @@ -261,8 +263,19 @@ main(int argc, char **argv) #endif /* !_WIN32 */ start_server(flags); - shutdwn(empth_wait_for_shutdown()); + for (;;) { + sig = empth_wait_for_signal(); +#ifdef SIGHUP + if (sig == SIGHUP) { + journal_close(); + journal_open(); + continue; + } +#endif + break; + } + shutdwn(sig); CANT_REACH(); finish_server(); return EXIT_SUCCESS;