#define SUPPRESS_COMPILER_INLINES
#include "std.h"
#include "file_incl.h"
#include "lpc_incl.h"
#include "lex.h"
#include "backend.h"
#include "simul_efun.h"
#include "binaries.h"
#include "main.h"
#include "otable.h"
#include "comm.h"
#include "compiler.h"
#include "port.h"
#include "md.h"
#include "main.h"
#include "compile_file.h"
#include "socket_efuns.h"
port_def_t external_port[5];
static int e_flag = 0; /* Load empty, without preloads. */
#ifdef DEBUG
int d_flag = 0; /* Run with debug */
#endif
int t_flag = 0; /* Disable heart beat and reset */
int comp_flag = 0; /* Trace compilations */
int max_cost;
int time_to_swap;
int time_to_clean_up;
char *default_fail_message;
int boot_time;
int max_array_size;
int max_buffer_size;
int max_string_length;
char *master_file_name;
static int reserved_size;
char *reserved_area; /* reserved for MALLOC() */
static char *mud_lib;
svalue_t const0, const1, const0u, const0n;
double consts[NUM_CONSTS];
/* -1 indicates that we have never had a master object. This is so the
* simul_efun object can load before the master. */
object_t *master_ob = (object_t *) -1;
#ifndef NO_IP_DEMON
void init_addr_server();
#endif /* NO_IP_DEMON */
#ifdef TRAP_CRASHES
#ifdef SIGNAL_FUNC_TAKES_INT
static void sig_usr1 PROT((int));
static void sig_term PROT((int));
static void sig_int PROT((int));
#ifndef DEBUG
static void sig_hup PROT((int)),
sig_abrt PROT((int)),
sig_segv PROT((int)),
sig_ill PROT((int)),
sig_bus PROT((int)),
sig_fpe PROT((int)),
sig_iot PROT((int));
#endif /* DEBUG */
#else
static void sig_usr1 PROT((void));
static void sig_term PROT((void));
static void sig_int PROT((void));
#ifndef DEBUG
static void sig_hup PROT((void)),
sig_abrt PROT((void)),
sig_segv PROT((void)),
sig_ill PROT((void)),
sig_bus PROT((void)),
sig_fpe PROT((void)),
sig_iot PROT((void));
#endif /* DEBUG */
#endif /* SIGNAL_FUNC_TAKES_INT */
#endif /* TRAP_CRASHES */
#ifdef DEBUG_MACRO
/* used by debug.h: please leave this in here -- Tru (you can change its
value if you like).
*/
int debug_level = 32768;
#endif /* DEBUG_MACRO */
int main P2(int, argc, char **, argv)
{
time_t tm;
int i, new_mudlib = 0, got_defaults = 0;
int no_ip_demon = 0;
char *p;
char version_buf[80];
#if 0
int dtablesize;
#endif
error_context_t econ;
#if !defined(LATTICE) && !defined(OLD_ULTRIX) && !defined(sequent) && \
!defined(sgi)
void tzset();
#endif
struct lpc_predef_s predefs;
#if !defined(__SASC) && (defined(AMITCP) || defined(AS225))
amiga_sockinit();
atexit(amiga_sockexit);
#endif
#ifdef WRAPPEDMALLOC
wrappedmalloc_init();
#endif /* WRAPPEDMALLOC */
#ifdef DEBUGMALLOC
MDinit();
#endif
#if (defined(PROFILING) && !defined(PROFILE_ON) && defined(HAS_MONCONTROL))
moncontrol(0);
#endif
#if !defined(OLD_ULTRIX) && !defined(LATTICE) && !defined(sequent)
tzset();
#endif
boot_time = get_current_time();
const0.type = T_NUMBER;
const0.u.number = 0;
const1.type = T_NUMBER;
const1.u.number = 1;
/* const0u used by undefinedp() */
const0u.type = T_NUMBER;
const0u.subtype = T_UNDEFINED;
const0u.u.number = 0;
/* const0n used by nullp() */
const0n.type = T_NUMBER;
const0n.subtype = T_NULLVALUE;
const0n.u.number = 0;
fake_prog.program_size = 0;
/*
* Check that the definition of EXTRACT_UCHAR() is correct.
*/
p = (char *) &i;
*p = -10;
if (EXTRACT_UCHAR(p) != 0x100 - 10) {
fprintf(stderr, "Bad definition of EXTRACT_UCHAR() in interpret.h.\n");
exit(-1);
}
/*
* An added test: can we do EXTRACT_UCHAR(x++)?
* (read_number, etc uses it)
*/
p = (char *) &i;
(void) EXTRACT_UCHAR(p++);
if ((p - (char *) &i) != 1) {
fprintf(stderr, "EXTRACT_UCHAR() in interpret.h evaluates its argument more than once.\n");
exit(-1);
}
/*
* Check the living hash table size
*/
if (LIVING_HASH_SIZE != 4 && LIVING_HASH_SIZE != 16 &&
LIVING_HASH_SIZE != 64 && LIVING_HASH_SIZE != 256 &&
LIVING_HASH_SIZE != 1024 && LIVING_HASH_SIZE != 4096) {
fprintf(stderr, "LIVING_HASH_SIZE in options.h must be one of 4, 16, 64, 256, 1024, 4096, ...\n");
exit(-1);
}
#ifdef RAND
srand(get_current_time());
#else
# ifdef DRAND48
srand48(get_current_time());
# else
# ifdef RANDOM
srandom(get_current_time());
# else
fprintf(stderr, "Warning: no random number generator specified!\n");
# endif
# endif
#endif
current_time = get_current_time();
/*
* Initialize the microsecond clock.
*/
init_usec_clock();
/* read in the configuration file */
got_defaults = 0;
for (i = 1; (i < argc) && !got_defaults; i++) {
if (argv[i][0] != '-') {
set_defaults(argv[i]);
got_defaults = 1;
}
}
if (!got_defaults) {
fprintf(stderr, "You must specify the configuration filename as an argument.\n");
exit(-1);
}
printf("Initializing internal tables....\n");
init_strings(); /* in stralloc.c */
init_otable(); /* in otable.c */
init_identifiers(); /* in lex.c */
init_locals(); /* in compiler.c */
/* disable this for now */
#if 0
/*
* We estimate that we will need MAX_USERS + MAX_EFUN_SOCKS + 10 file
* descriptors if the maximum number of users were to log in and all LPC
* sockets were in use. This is a pretty close estimate.
*/
#ifndef LATTICE
dtablesize = MAX_USERS + MAX_EFUN_SOCKS + 10;
#else
/*
* Amiga sockets separate from file descriptors
*/
dtablesize = MAX_USERS + MAX_EFUN_SOCKS;
#endif
/*
* If our estimate is larger than FD_SETSIZE, then we need more file
* descriptors than the operating system can handle. This is a problem
* that can be resolved by decreasing MAX_USERS, MAX_EFUN_SOCKS, or both.
*/
if (dtablesize > FD_SETSIZE) {
fprintf(stderr, "Warning: File descriptor requirements exceed system capacity!\n");
fprintf(stderr, " Configuration exceeds system capacity by %d descriptor(s).\n",
dtablesize - FD_SETSIZE);
}
#ifdef HAS_SETDTABLESIZE
/*
* If the operating system supports setdtablesize() then we can request
* the number of file descriptors we really need. First check to see if
* wee already have enough. If so dont bother the OS. If not, attempt to
* allocate the number we estimated above. There are system imposed
* limits on file descriptors, so we may not get as many as we asked for.
* Check to make sure we get enough.
*/
if (getdtablesize() < dtablesize)
if (setdtablesize(dtablesize) < dtablesize) {
fprintf(stderr, "Warning: Could not allocate enough file descriptors!\n");
fprintf(stderr, " setdtablesize() could not allocate %d descriptor(s).\n",
getdtablesize() - dtablesize);
}
/*
* Just be polite and tell the administrator how many he has.
*/
fprintf(stderr, "%d file descriptors were allocated, (%d were requested).\n",
getdtablesize(), dtablesize);
#endif
#endif
time_to_clean_up = TIME_TO_CLEAN_UP;
time_to_swap = TIME_TO_SWAP;
max_cost = MAX_COST;
reserved_size = RESERVED_SIZE;
max_array_size = MAX_ARRAY_SIZE;
max_buffer_size = MAX_BUFFER_SIZE;
max_string_length = MAX_STRING_LENGTH;
master_file_name = (char *) MASTER_FILE;
/* fix the filename */
while (*master_file_name == '/') master_file_name++;
p = master_file_name;
while (*p++);
if (p[-2]=='c' && p[-3]=='.')
p[-3]=0;
mud_lib = (char *) MUD_LIB;
set_inc_list(INCLUDE_DIRS);
if (reserved_size > 0)
reserved_area = (char *) DMALLOC(reserved_size, TAG_RESERVED, "main.c: reserved_area");
for (i = 0; i < sizeof consts / sizeof consts[0]; i++)
consts[i] = exp(-i / 900.0);
init_num_args();
reset_machine(1);
/*
* The flags are parsed twice ! The first time, we only search for the -m
* flag, which specifies another mudlib, and the D-flags, so that they
* will be available when compiling master.c.
*/
for (i = 1; i < argc; i++) {
if (argv[i][0] != '-')
continue;
switch (argv[i][1]) {
case 'D':
if (argv[i][2]) { /* Amylaar : allow flags to be passed down to
* the LPC preprocessor */
struct lpc_predef_s *tmp;
tmp = &predefs;
tmp->flag = argv[i] + 2;
tmp->next = lpc_predefs;
lpc_predefs = tmp;
continue;
}
fprintf(stderr, "Illegal flag syntax: %s\n", argv[i]);
exit(-1);
case 'N':
no_ip_demon++;
continue;
#ifdef YYDEBUG
case 'y':
yydebug = 1;
continue;
#endif /* YYDEBUG */
case 'm':
mud_lib = alloc_cstring(argv[i] + 2, "mudlib dir");
if (chdir(mud_lib) == -1) {
fprintf(stderr, "Bad mudlib directory: %s\n", mud_lib);
exit(-1);
}
new_mudlib = 1;
break;
}
}
if (!new_mudlib && chdir(mud_lib) == -1) {
fprintf(stderr, "Bad mudlib directory: %s\n", mud_lib);
exit(-1);
}
get_version(version_buf);
time(&tm);
debug_message("----------------------------------------------------------------------------\n%s (%s) starting up on %s - %s\n\n", MUD_NAME, version_buf, ARCH, ctime(&tm));
#ifdef BINARIES
init_binaries(argc, argv);
#endif
#ifdef LPC_TO_C
init_lpc_to_c();
#endif
add_predefines();
#ifndef NO_IP_DEMON
if (!no_ip_demon && ADDR_SERVER_IP)
init_addr_server(ADDR_SERVER_IP, ADDR_SERVER_PORT);
#endif /* NO_IP_DEMON */
eval_cost = max_cost; /* needed for create() functions */
save_context(&econ);
if (SETJMP(econ.context)) {
debug_message("The simul_efun (%s) and master (%s) objects must be loadable.\n",
SIMUL_EFUN, MASTER_FILE);
exit(-1);
} else {
init_simul_efun(SIMUL_EFUN);
init_master(MASTER_FILE);
}
pop_context(&econ);
for (i = 1; i < argc; i++) {
if (argv[i][0] != '-') {
continue;
} else {
/*
* Look at flags. -m and -o has already been tested.
*/
switch (argv[i][1]) {
case 'D':
case 'N':
case 'm':
case 'y':
continue;
case 'f':
save_context(&econ);
if (SETJMP(econ.context)) {
debug_message("Error while calling master::flag(\"%s\"), aborting ...", argv[i] + 2);
exit(-1);
}
push_constant_string(argv[i] + 2);
(void) apply_master_ob(APPLY_FLAG, 1);
if (MudOS_is_being_shut_down) {
debug_message("Shutdown by master object.\n");
exit(0);
}
pop_context(&econ);
continue;
case 'e':
e_flag++;
continue;
case 'p':
external_port[0].port = atoi(argv[i] + 2);
continue;
case 'd':
#ifdef DEBUG
d_flag++;
#else
debug_message("Driver must be compiled with DEBUG on to use -d.\n");
#endif
case 'c':
comp_flag++;
continue;
case 't':
t_flag++;
continue;
default:
debug_message("Unknown flag: %s\n", argv[i]);
exit(-1);
}
}
}
if (MudOS_is_being_shut_down)
exit(1);
if (strlen(DEFAULT_FAIL_MESSAGE))
default_fail_message = DEFAULT_FAIL_MESSAGE;
else
default_fail_message = "What?";
#ifdef PACKAGE_MUDLIB_STATS
restore_stat_files();
#endif
#ifdef PACKAGE_SOCKETS
init_sockets(); /* initialize efun sockets */
#endif
preload_objects(e_flag);
#ifdef TRAP_CRASHES
#ifdef SIGUSR1
signal(SIGUSR1, sig_usr1);
#endif
signal(SIGTERM, sig_term);
signal(SIGINT, sig_int);
#ifndef DEBUG
#if defined(SIGABRT) && !defined(LATTICE)
signal(SIGABRT, sig_abrt);
#endif
#ifdef SIGIOT
signal(SIGIOT, sig_iot);
#endif
#ifdef SIGHUP
signal(SIGHUP, sig_hup);
#endif
#ifdef SIGBUS
signal(SIGBUS, sig_bus);
#endif
#ifdef SIGFPE
signal(SIGFPE, sig_fpe);
#endif
#ifndef LATTICE
signal(SIGSEGV, sig_segv);
signal(SIGILL, sig_ill);
#endif
#endif /* DEBUG */
#endif
backend();
return 0;
}
#ifdef DEBUGMALLOC
char *int_string_copy P2(char *, str, char *, desc)
#else
char *int_string_copy P1(char *, str)
#endif
{
char *p;
int len;
DEBUG_CHECK(!str, "Null string passed to string_copy.\n");
len = strlen(str);
if (len > max_string_length) {
len = max_string_length;
p = new_string(len, desc);
(void) strncpy(p, str, len);
p[len] = '\0';
} else {
p = new_string(len, desc);
(void) strncpy(p, str, len + 1);
}
return p;
}
#ifdef DEBUGMALLOC
char *int_string_unlink P2(char *, str, char *, desc)
#else
char *int_string_unlink P1(char *, str)
#endif
{
malloc_block_t *mbt, *newmbt;
mbt = ((malloc_block_t *)str) - 1;
mbt->ref--;
if (mbt->size == USHRT_MAX) {
int l = strlen(str + USHRT_MAX) + USHRT_MAX; /* ouch */
newmbt = (malloc_block_t *)DXALLOC(l + sizeof(malloc_block_t) + 1, TAG_MALLOC_STRING, desc);
memcpy((char *)(newmbt + 1), (char *)(mbt + 1), l+1);
newmbt->size = USHRT_MAX;
ADD_NEW_STRING(USHRT_MAX, sizeof(malloc_block_t));
} else {
newmbt = (malloc_block_t *)DXALLOC(mbt->size + sizeof(malloc_block_t) + 1, TAG_MALLOC_STRING, desc);
memcpy((char *)(newmbt + 1), (char *)(mbt + 1), mbt->size+1);
newmbt->size = mbt->size;
ADD_NEW_STRING(mbt->size, sizeof(malloc_block_t));
}
newmbt->ref = 1;
CHECK_STRING_STATS;
return (char *)(newmbt + 1);
}
void debug_message P1V(char *, fmt)
{
static int append = 0;
static char deb_buf[100];
static char *deb = deb_buf;
va_list args;
FILE *fp = NULL;
V_DCL(char *fmt);
if (!append) {
/*
* check whether config file specified this option
*/
if (strlen(DEBUG_LOG_FILE))
sprintf(deb, "%s/%s", LOG_DIR, DEBUG_LOG_FILE);
else
sprintf(deb, "%s/debug.log", LOG_DIR);
while (*deb == '/')
deb++;
}
fp = fopen(deb, append ? "a" : "w");
/*
* re-use stdout's file descriptor if system or process runs out
*
* OS/2 doesn't have ENFILE.
*/
if (!fp && (errno == EMFILE
#ifdef ENFILE
|| errno == ENFILE
#endif
)) {
fp = freopen(deb, append ? "a" : "w", stdout);
append = 2;
}
if (!fp) {
/* darn. We're in trouble */
perror(deb);
abort();
}
V_START(args, fmt);
V_VAR(char *, fmt, args);
vfprintf(fp, fmt, args);
fflush(fp);
vfprintf(stderr, fmt, args);
fflush(stderr);
va_end(args);
/*
* don't close stdout
*/
if (append != 2)
(void) fclose(fp);
/*
* append to debug.log next time thru
*/
if (!append)
append = 1;
}
int slow_shut_down_to_do = 0;
char *xalloc P1(int, size)
{
char *p;
static int going_to_exit;
if (going_to_exit)
exit(3);
#ifdef DEBUG
if (size == 0)
fatal("Tried to allocate 0 bytes.\n");
#endif
p = (char *) DMALLOC(size, TAG_MISC, "main.c: xalloc");
if (p == 0) {
if (reserved_area) {
FREE(reserved_area);
p = "Temporarily out of MEMORY. Freeing reserve.\n";
write(1, p, strlen(p));
reserved_area = 0;
slow_shut_down_to_do = 6;
return xalloc(size);/* Try again */
}
going_to_exit = 1;
fatal("Totally out of MEMORY.\n");
}
return p;
}
#ifdef TRAP_CRASHES
/* send this signal when the machine is about to reboot. The script
which restarts the MUD should take an exit code of 1 to mean don't
restart
*/
#ifdef SIGNAL_FUNC_TAKES_INT
static void sig_usr1 P1(int, sig)
#else
static void sig_usr1()
#endif
{
push_string("Host machine shutting down", STRING_CONSTANT);
push_undefined();
push_undefined();
apply_master_ob(APPLY_CRASH, 3);
debug_message("Received SIGUSR1, calling exit(-1)\n");
exit(-1);
}
/*
* Actually, doing all this stuff from a signal is probably illegal
* -Beek
*/
#ifdef SIGNAL_FUNC_TAKES_INT
static void sig_term P1(int, sig)
#else
static void sig_term()
#endif
{
fatal("Process terminated");
}
#ifdef SIGNAL_FUNC_TAKES_INT
static void sig_int P1(int, sig)
#else
static void sig_int()
#endif
{
fatal("Process interrupted");
}
#ifndef DEBUG
#ifdef SIGNAL_FUNC_TAKES_INT
static void sig_segv P1(int, sig)
#else
static void sig_segv()
#endif
{
fatal("Segmentation fault");
}
#ifdef SIGNAL_FUNC_TAKES_INT
static void sig_bus P1(int, sig)
#else
static void sig_bus()
#endif
{
fatal("Bus error");
}
#ifdef SIGNAL_FUNC_TAKES_INT
static void sig_fpe P1(int, sig)
#else
static void sig_fpe()
#endif
{
}
#ifdef SIGNAL_FUNC_TAKES_INT
static void sig_ill P1(int, sig)
#else
static void sig_ill()
#endif
{
fatal("Illegal instruction");
}
#ifdef SIGNAL_FUNC_TAKES_INT
static void sig_hup P1(int, sig)
#else
static void sig_hup()
#endif
{
fatal("Hangup!");
}
#ifdef SIGNAL_FUNC_TAKES_INT
static void sig_abrt P1(int, sig)
#else
static void sig_abrt()
#endif
{
fatal("Aborted");
}
#ifdef SIGNAL_FUNC_TAKES_INT
static void sig_iot P1(int, sig)
#else
static void sig_iot()
#endif
{
fatal("Aborted(IOT)");
}
#endif /* !DEBUG */
#endif /* TRAP_CRASHES */