/* DLIFE Copyright (C) 2000 Richard W.M. Jones * and other authors listed in the ``AUTHORS'' file. * * 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. * * $Id: main.c,v 1.3 2002/12/11 17:16:21 rich Exp $ */ #include "config.h" #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_PWD_H #include #endif #ifdef HAVE_GRP_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYSLOG_H #include #endif #include "cell.h" #include "soup.h" #include "load.h" #include "params.h" #include "random.h" #include "state.h" #include "image.h" unsigned soup_fetch_failure = 1000000; unsigned inc_pc_failure = 1000000; unsigned insn_exec_failure = 1000000; unsigned access_control_failure = 10; unsigned cell_initialization_failure = 1000000; int reaper_invoke_threshold = 80; int reaper_reap_threshold = 79; int save_period = 5; int outgoing_period = 10; int incoming_period = 60; int info_period = 60; int max_cells_incoming_per_pass = 4; int verbose = 0; static int soup_size = 128*1024; /* Read from configuration file. */ static const char *conf_file = CONFDIR "/soup.conf"; static const char *save_dir = SPOOLDIR; static void parse_args (int argc, char *argv[]); static void read_config_file (void); static int detect_nr_cpus (void); int main (int argc, char *argv[]) { char filename[256]; int nr_cpus, i; /* Parse the command line. */ parse_args (argc, argv); /* Read the configuration file. */ read_config_file (); /* Initialize stuff. */ random_init (); #ifdef HAVE_OPENLOG /* Open connection to syslog. */ openlog ("dlife_soup", LOG_PID, LOG_DAEMON); #endif /* Find out how many processors are available. */ nr_cpus = detect_nr_cpus (); /* Find existing saves directory. If there is a soup image in there, * then we will load it. Otherwise we will start with the god cell. */ if (chdir (save_dir) < 0) { perror (save_dir); exit (1); } #ifdef HAVE_NICE /* Reduce our priority down to the minimum. */ nice (64); #endif #if defined(HAVE_GETUID) && defined(HAVE_SETUID) && defined(HAVE_SETGID) && defined(HAVE_GETPWNAM) && defined(HAVE_INITGROUPS) /* If we are running as root, change to user dlife. */ if (getuid () == 0) { struct passwd *pw = getpwnam ("dlife"); if (pw) { initgroups ("dlife", pw->pw_gid); setgid (pw->pw_gid); setuid (pw->pw_uid); } else { fprintf (stderr, "cannot change to user/group dlife"); } } #endif #ifdef HAVE_SYSLOG syslog (LOG_INFO, "version " VERSION " starting [conf=" CONFDIR ", spool=" SPOOLDIR ", cpus=%d]", nr_cpus); #endif /* Fork once for each processor. */ for (i = 0; i < nr_cpus; ++i) { int pid; pid = fork (); if (pid < 0) { perror ("fork"); abort (); } if (pid == 0) { /* This is the child process. */ struct state *cpu_state; /* Try to load the previous soup image. If the soup image * cannot be found, then instead load the god cell. */ sprintf (filename, "saved/soup%d.img", i); cpu_state = image_load (filename, soup_size, i); if (cpu_state) { if (verbose) printf ("CPU %d: starting from previous image file.\n", i); } else { struct cell *god; if (verbose) printf ("CPU %d: no soup image found, loading god cell\n", i); cpu_state = state_malloc (soup_size, i); if ((god = load_cell (cpu_state, "god.dlo")) == 0) { fprintf (stderr, "dlife_soup: cannot load god cell god.dlo\n"); #ifdef HAVE_SYSLOG syslog (LOG_ERR, "cannot load god cell " SPOOLDIR "/god.dlo -- exiting"); #endif abort (); } cell_activate (cpu_state, god); } cpu_state->filename = strdup (filename); /* Detach from the terminal. */ close (0); close (1); close (2); setsid (); /* Start running. */ run_thread (cpu_state); exit (0); } } /* Parent process exits. The children will automatically be * cleaned up by init(8). */ exit (0); } /* Parse the command line arguments. */ static void parse_args (int argc, char *argv[]) { int c; while ((c = getopt (argc, argv, "f:r:v")) != -1) { switch (c) { case 'f': conf_file = optarg; break; case 'r': save_dir = optarg; break; case 'v': verbose = 1; break; default: fprintf (stderr, "usage: dlife_soup [-f conf-file] [-r save-dir] [-v]\n"); exit (1); } } } /* Return true if n is a power of 2. */ static int is_power_2 (int n) { while ((n & 1) == 0) n >>= 1; return n == 1; } static void read_config_file (void) { FILE *fp; char buffer[256], *t; fp = fopen (conf_file, "r"); if (fp == 0) { if (verbose) printf ("No configuration file found.\n"); return; } while (fgets (buffer, sizeof buffer, fp) != 0) { /* Remove trailing \n and \r. */ t = buffer + strlen (buffer) - 1; while (t >= buffer && (*t == '\n' || *t == '\r')) *t-- = '\0'; /* Remove any comments (after a ``#'' character). */ t = strchr (buffer, '#'); if (t) *t = '\0'; /* Look for lines which we understand. */ if (sscanf (buffer, "soup_fetch_failure %u", &soup_fetch_failure) == 1) { /* No checks required. */ continue; } if (sscanf (buffer, "inc_pc_failure %u", &inc_pc_failure) == 1) { /* No checks required. */ continue; } if (sscanf (buffer, "insn_exec_failure %u", &insn_exec_failure) == 1) { /* No checks required. */ continue; } if (sscanf (buffer, "access_control_failure %u", &access_control_failure) == 1) { /* No checks required. */ continue; } if (sscanf (buffer, "cell_initialization_failure %u", &cell_initialization_failure) == 1) { /* No checks required. */ continue; } if (sscanf (buffer, "reaper_invoke_threshold %d", &reaper_invoke_threshold) == 1) { if (reaper_invoke_threshold < 0 || reaper_invoke_threshold > 100) { fprintf (stderr, "reaper_invoke_threshold is a percentage: it must be 0 - 100\n"); exit (1); } continue; } if (sscanf (buffer, "reaper_reap_threshold %d", &reaper_reap_threshold) == 1) { if (reaper_reap_threshold < 0 || reaper_reap_threshold > 100) { fprintf (stderr, "reaper_reap_threshold is a percentage: it must be 0 - 100\n"); exit (1); } continue; } if (sscanf (buffer, "soup_size %d", &soup_size) == 1) { if (soup_size <= 0 || ! is_power_2 (soup_size)) { fprintf (stderr, "soup_size must be a power of 2\n"); exit (1); } continue; } if (sscanf (buffer, "save_period %d", &save_period) == 1) { /* No checks required. */ continue; } if (sscanf (buffer, "outgoing_period %d", &outgoing_period) == 1) { /* No checks required. */ continue; } if (sscanf (buffer, "incoming_period %d", &incoming_period) == 1) { /* No checks required. */ continue; } if (sscanf (buffer, "info_period %d", &info_period) == 1) { /* No checks required. */ continue; } } } /* Detect the number of CPUs available. This is very operating system * specific. */ #ifdef linux #ifdef __alpha__ static int detect_nr_cpus () { FILE *fp; int n = -1; char line[256]; fp = fopen ("/proc/cpuinfo", "r"); if (fp == 0) { perror ("/proc/cpuinfo"); fprintf (stderr, "warning: cannot detect number of CPUs available\n"); return 1; } while (fgets (line, sizeof line, fp)) { if (sscanf (line, "cpus detected : %d", &n) == 1) break; } fclose (fp); if (verbose) printf ("number of CPUs detected: %d\n", n); if (n <= 0) { fprintf (stderr, "warning: cannot detect number of CPUs available\n"); return 1; } return n; } #elif __sparc__ static int detect_nr_cpus () { FILE *fp; int n = -1; char line[256]; fp = fopen ("/proc/cpuinfo", "r"); if (fp == 0) { perror ("/proc/cpuinfo"); fprintf (stderr, "warning: cannot detect number of CPUs available\n"); return 1; } while (fgets (line, sizeof line, fp)) { if (sscanf (line, "ncpus active : %d", &n) == 1) break; } fclose (fp); if (verbose) printf ("number of CPUs detected: %d\n", n); if (n <= 0) { fprintf (stderr, "warning: cannot detect number of CPUs available\n"); return 1; } return n; } #else /* !__alpha__ || __sparc__ */ static int detect_nr_cpus () { FILE *fp; int n, c = 0; char line[256]; fp = fopen ("/proc/cpuinfo", "r"); if (fp == 0) { perror ("/proc/cpuinfo"); fprintf (stderr, "warning: cannot detect number of CPUs available\n"); return 1; } while (fgets (line, sizeof line, fp)) { if (sscanf (line, "processor : %d", &n) == 1 && n+1 > c) { c = n+1; } } fclose (fp); if (verbose) printf ("number of CPUs detected: %d\n", c); if (c <= 0) { fprintf (stderr, "warning: cannot detect number of CPUs available\n"); return 1; } return c; } #endif /* !__alpha__ */ #else /* !linux */ static void detect_nr_cpus () { fprintf (stderr, "warning: cannot detect number of CPUs available on this platform\n"); return 1; } #endif