--- freem/src/mumps.c 2025/03/24 16:10:48 1.8 +++ freem/src/mumps.c 2025/04/16 17:36:12 1.26 @@ -1,5 +1,5 @@ /* - * $Id: mumps.c,v 1.8 2025/03/24 16:10:48 snw Exp $ + * $Id: mumps.c,v 1.26 2025/04/16 17:36:12 snw Exp $ * main module of freem * * @@ -24,6 +24,60 @@ * along with FreeM. If not, see . * * $Log: mumps.c,v $ + * Revision 1.26 2025/04/16 17:36:12 snw + * Add FreeBSD shm cleanup script + * + * Revision 1.25 2025/04/16 05:57:42 snw + * Remove non-useful procctl calls + * + * Revision 1.24 2025/04/16 05:37:06 snw + * Refine FreeBSD ASLR fix + * + * Revision 1.23 2025/04/16 05:33:15 snw + * Try to use procctl function to fix ASLR problem on FreeBSD + * + * Revision 1.22 2025/04/15 16:49:36 snw + * Make use of logprintf throughout codebase + * + * Revision 1.21 2025/04/15 02:24:43 snw + * Improve FreeM logging capabilities + * + * Revision 1.20 2025/04/13 04:22:43 snw + * Fix snprintf calls + * + * Revision 1.19 2025/04/10 01:24:38 snw + * Remove C++ style comments + * + * Revision 1.18 2025/04/09 19:52:02 snw + * Eliminate as many warnings as possible while building with -Wall + * + * Revision 1.17 2025/04/04 21:28:16 snw + * Remove custom_user and custom_group vars from freem and shed privileges per environment catalog settings + * + * Revision 1.16 2025/04/04 19:43:18 snw + * Switch to using environment catalog to determine user and group for environment, and remove -u and -g flags from freem + * + * Revision 1.15 2025/04/03 20:48:14 snw + * Improve daemon error diagnostics and bump to 0.63.0-rc3 + * + * Revision 1.14 2025/04/02 04:50:49 snw + * Allow vendor routines to be upgraded + * + * Revision 1.13 2025/04/02 03:26:22 snw + * Don't corrupt the terminal if FreeM runs before fmadm configure has been run + * + * Revision 1.12 2025/04/02 02:16:27 snw + * Add fmadm status environment command and move journals to a better location + * + * Revision 1.11 2025/04/01 23:21:45 snw + * fmadm commands for stopping, starting, and restarting environments now functional + * + * Revision 1.10 2025/04/01 20:11:46 snw + * Further work on fmadm + * + * Revision 1.9 2025/03/31 20:01:13 snw + * Set d_uid in daemon + * * Revision 1.8 2025/03/24 16:10:48 snw * Print error message and exit on OS/2 if daemon is run without --nofork * @@ -44,6 +98,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later **/ +#define _GNU_SOURCE #include #include #include "mpsdef.h" @@ -72,8 +127,7 @@ #include #include #include - - +#include "log.h" #if defined(HAVE_GETOPT_H) # include #endif @@ -87,7 +141,6 @@ extern char *getenv(const char *name); void freem_usage(void); void freem_print_version(void); void init_ztrap(void); -void m_log (int, const char *); int main (int argc, char **argv, char **envp) { @@ -100,6 +153,8 @@ int main (int argc, char **argv, char ** int option_index = 0; + char fm_initialized = FALSE; + char dx_mcode[512]; char startup_routine[256]; short routine_mode; @@ -114,9 +169,6 @@ int main (int argc, char **argv, char ** gid_t d_gid; uid_t d_uid; - short custom_user = FALSE; - short custom_group = FALSE; - #if defined(HAVE_GETOPT_LONG) struct option long_options[] = { {"help", no_argument, 0, 'h'}, @@ -132,7 +184,6 @@ int main (int argc, char **argv, char ** {"execute", required_argument, 0, 'x'}, {"daemon", no_argument, 0, 'd'}, {"nofork", no_argument, 0, 'k'}, - {"pidfile", required_argument, 0, 'p'}, {"shmsize", required_argument, 0, 'S'}, {"user", required_argument, 0, 'u'}, {"group", required_argument, 0, 'g'}, @@ -146,14 +197,13 @@ int main (int argc, char **argv, char ** char *symname = (char *) calloc(STRLEN, sizeof(char)); char *symval = (char *) calloc(STRLEN, sizeof(char)); - - int namelen; - int vallen; - + char cli_rtn_path[PATH_MAX] = {0}; char *cli_rtn_file; char cli_rtn_name[256]; + char env_ena[25]; + routine_mode = FALSE; strcpy (m_dialect, "FREEM"); @@ -171,7 +221,6 @@ int main (int argc, char **argv, char ** strcpy (stack0, argv[0]); stcnv_c2m (stack0); - /* strncpy (config_file, SYSCONFDIR"/freem.conf", 100); */ @@ -183,7 +232,7 @@ int main (int argc, char **argv, char ** while (1) { - c = getopt_long (argc, argv, "hsfiqRr:n:e:vx:dkpS:u:g:", long_options, &option_index); + c = getopt_long (argc, argv, "hsfiqRr:n:e:vx:dkpS", long_options, &option_index); if (c == -1) break; if (c == '?') freem_usage (); @@ -206,7 +255,7 @@ int main (int argc, char **argv, char ** break; case 'e': /* specify FreeM environment */ - strncpy (shm_env, optarg, 255); + strncpy (shm_env, optarg, sizeof (shm_env) - 1); break; case 'R': @@ -294,24 +343,9 @@ int main (int argc, char **argv, char ** nofork = TRUE; break; - case 'p': /* --pidfile */ - pid_file_path = strdup (optarg); - break; - case 'S': /* --shmsize */ shm_init_size = atol (optarg); - break; - - case 'u': /* --user */ - strncpy (d_username, optarg, 40); - custom_user = TRUE; - break; - - case 'g': /* --group */ - strncpy (d_groupname, optarg, 40); - custom_group = TRUE; - break; - + break; } @@ -323,7 +357,7 @@ int main (int argc, char **argv, char ** extern char *optarg; extern int optind, optopt; - while ((c = getopt (argc, argv, "hsfiqRr:n:e:vx:dkpS:u:g:")) != -1) { + while ((c = getopt (argc, argv, "hsfiqRr:n:e:vx:dkS:")) != -1) { if (c == '?') freem_usage (); @@ -346,7 +380,7 @@ int main (int argc, char **argv, char ** break; case 'e': /* specify FreeM environment */ - strncpy (shm_env, optarg, 255); + strncpy (shm_env, optarg, sizeof (shm_env) - 1); break; case 'R': @@ -390,10 +424,6 @@ int main (int argc, char **argv, char ** nofork = TRUE; break; - case 'p': /* --pidfile */ - pid_file_path = strdup (optarg); - break; - case 's': /* --standard */ if (strcmp (optarg, "M77") == 0) { @@ -435,17 +465,6 @@ int main (int argc, char **argv, char ** shm_init_size = atol (optarg); break; - case 'u': /* --user */ - strncpy (d_username, optarg, 40); - custom_user = TRUE; - break; - - case 'g': /* --group */ - strncpy (d_groupname, optarg, 40); - custom_group = TRUE; - break; - - } } } @@ -458,32 +477,56 @@ int main (int argc, char **argv, char ** } #endif - snprintf (config_file, 4096, "%s/freem/%s/freem.conf", SYSCONFDIR, shm_env); + snprintf (config_file, sizeof (config_file) - 1, "%s/freem/%s/freem.conf", SYSCONFDIR, shm_env); + snprintf (env_config_file, sizeof (config_file) - 1, "%s/freem/env.conf", SYSCONFDIR); - if (run_daemon == TRUE && geteuid() == 0) { + if (!file_exists (env_config_file)) { + logprintf (FM_LOG_FATAL, "freem: environment catalog does not exist; may need to run fmadm configure"); + } - if (custom_group) { - d_grp = getgrnam (d_groupname); + if (!file_exists (config_file)) { + logprintf (FM_LOG_FATAL, "freem: configuration file for %s does not exist; may need to run fmadm configure", shm_env); + } - if (d_grp == NULL) { - fprintf (stderr, "freem: invalid group '%s'\n", d_groupname); - exit (1); - } - - d_gid = d_grp->gr_gid; - } + if (read_profile_string (env_config_file, shm_env, "user", d_username) == FALSE) { + logprintf (FM_LOG_FATAL, "freem: could not determine owning user for environment %s", shm_env); + } - if (custom_user) { - d_user = getpwnam (d_username); + if (read_profile_string (env_config_file, shm_env, "group", d_groupname) == FALSE) { + logprintf (FM_LOG_FATAL, "freem: could not determine owning group for environment %s", shm_env); + } - if (d_user == NULL) { - fprintf (stderr, "freem: invalid user '%s'\n", d_username); - exit (1); - } - - d_uid = d_user->pw_uid; - } + if (read_profile_string (env_config_file, shm_env, "enabled", env_ena) == FALSE) { + logprintf (FM_LOG_FATAL, "freem: could not discover enabled state for environment %s", shm_env); + } + + if (strcmp (env_ena, "true") != 0) { + logprintf (FM_LOG_FATAL, "freem: environment %s is administratively disabled", shm_env); + } + + d_grp = getgrnam (d_groupname); + if (d_grp == NULL) { + logprintf (FM_LOG_FATAL, "freem: invalid group '%s'", d_groupname); + } + d_gid = d_grp->gr_gid; + d_user = getpwnam (d_username); + if (d_user == NULL) { + logprintf (FM_LOG_FATAL, "freem: invalid user '%s'", d_username); + } + d_uid = d_user->pw_uid; + + +#if defined(__linux__) + if (run_daemon == FALSE && group_member (d_gid) == 0) { + logprintf (FM_LOG_FATAL, "freem: you must be a member of the %s group to use environment %s", d_groupname, shm_env); + } +#endif + + if (run_daemon == TRUE) { + if (geteuid () != 0 && nofork == FALSE) { + logprintf (FM_LOG_FATAL, "freem: forking daemon must be run as root"); + } } if ((nofork == TRUE) && (run_daemon == FALSE)) { @@ -494,15 +537,15 @@ int main (int argc, char **argv, char ** if ((run_daemon == TRUE) && (nofork == FALSE)) { int fork_fd; + + init_log (); /* daemonize */ fork_pid = fork (); if (fork_pid < 0) { - fprintf (stderr, "freem: failure in fork()\r\n"); - m_log (1, "failure in initial fork()\r\n"); - exit (1); + logprintf (FM_LOG_FATAL, "environment error: failure in initial fork()"); } if (fork_pid > 0) { @@ -510,9 +553,7 @@ int main (int argc, char **argv, char ** } if (setsid () < 0) { - fprintf (stderr, "freem: failure in setsid()\r\n"); - m_log (1, "failure in setsid()\r\n"); - exit (1); + logprintf (FM_LOG_FATAL, "environment error: failure in setsid()"); } signal (SIGCHLD, SIG_IGN); @@ -520,14 +561,12 @@ int main (int argc, char **argv, char ** fork_pid = fork (); if (fork_pid < 0) { - fprintf (stderr, "freem: failure in fork()\r\n"); - m_log (1, "failure in second fork()\r\n"); - exit (1); + logprintf (FM_LOG_FATAL, "environment error: failure in second fork()"); } if (fork_pid > 0) { + logprintf (FM_LOG_DEBUG, "environment: exiting from second fork()"); exit (0); - m_log (1, "exiting from second fork"); } umask (0); @@ -539,106 +578,67 @@ int main (int argc, char **argv, char ** } if (geteuid () == 0) { - /* shed privileges */ - if (custom_group) { - fprintf (stderr, "freem: switching to group %s\n", d_groupname); - m_log (1, "switching groups"); - - if (setgid (d_gid) == -1) { - fprintf (stderr, "freem: failure switching GID\n"); - m_log (1, "failure switching GIDs"); - exit (1); - } + /* shed privileges */ + logprintf (FM_LOG_INFO, "environment: switching to group %s", d_groupname); + + if (setgid (d_gid) == -1) { + logprintf (FM_LOG_FATAL, "environment error: failure switching GID"); } + + + if (d_uid != geteuid ()) { - if (custom_user) { - fprintf (stderr, "freem: switching to username %s\n", d_username); - m_log (1, "switching users"); + logprintf (FM_LOG_INFO, "environment: switching to username %s", d_username); if (setuid (d_uid) == -1) { - fprintf (stderr, "freem: failure switching UID\n"); - m_log (1, "failure switching UIDs"); - exit (1); + logprintf (FM_LOG_FATAL, "environment error: failure switching UID"); } - if (chdir (d_user->pw_dir) == -1) { - fprintf (stderr, "freem: chdir failure\n"); - m_log (1, "failure in chdir"); - exit (1); - } } + logprintf (FM_LOG_INFO, "environment: privilege shedding complete"); + } else { - fprintf (stderr, "not euid 0"); + logprintf (FM_LOG_INFO, "environment: not running as superuser; not shedding privileges"); } + logprintf (FM_LOG_INFO, "environment: reopening stdin, stdout, and stderr"); freopen ("/dev/null", "r", stdin); freopen ("/dev/null", "w+", stdout); freopen ("/dev/null", "w+", stderr); + logprintf (FM_LOG_INFO, "environment: stdin, stdout, and stderr reopened"); run_daemon = TRUE; nofork = FALSE; - if (pid_file_path == NULL) { - /* no PID file specified. choose one. */ - uid_t pid_uid; - char *home_directory; - - pid_file_path = (char *) calloc (PATH_MAX, sizeof (char)); - NULLPTRCHK(pid_file_path,"main"); - - home_directory = (char *) calloc (PATH_MAX, sizeof (char)); - NULLPTRCHK(home_directory,"main"); - - pid_uid = geteuid (); - - if (pid_uid == 0) { - /* we're running as root */ - strcpy (pid_file_path, "/var/run/freem.pid"); - } - else { - /* our user is a normie */ - struct passwd *pw = getpwuid (pid_uid); - - if (pw == NULL) { - m_log (1, "main: failure in getpwuid()"); - } - - strcpy (home_directory, pw->pw_dir); - snprintf (pid_file_path, PATH_MAX - 1, "%s/.freem.pid", home_directory); - } - - free (home_directory); - - } - { char pidfile_buf[256]; int errsav; - m_log (1, pid_file_path); + pid_file_path = (char *) malloc (PATH_MAX * sizeof (char)); + NULLPTRCHK(pid_file_path,"main"); + + snprintf (pid_file_path, PATH_MAX - 1, "%s/freem/run/%s.pid", LOCALSTATEDIR, shm_env); + logprintf (FM_LOG_INFO, "environment: opening pid file %s", pid_file_path); pid_fd = open (pid_file_path, O_RDWR | O_CREAT, 0640); errsav = errno; if (pid_fd < 0) { - m_log (1, "freem: could not open PID file"); - m_log (1, strerror (errsav)); - exit (1); + logprintf (FM_LOG_FATAL, "environment error: could not open PID file %s [%s]", pid_file_path, strerror (errsav)); } if (lockf (pid_fd, F_TLOCK, 0) < 0) { errsav = errno; - m_log (1, "freem: could not lock PID file - perhaps already running?"); - m_log (1, strerror (errsav)); - exit (1); + logprintf (FM_LOG_FATAL, "environment error: could not lock PID file [%s]", strerror (errsav)); } - sprintf (pidfile_buf, "%d\n", getpid ()); + sprintf (pidfile_buf, "%ld\n", (long) getpid ()); + logprintf (FM_LOG_INFO, "environment: writing pid file"); write (pid_fd, pidfile_buf, strlen (pidfile_buf)); - + } @@ -668,15 +668,18 @@ int main (int argc, char **argv, char ** skip_init = 1; /* initialize FreeM environment */ - strncpy (nsnbuf, nsname, 255); + strncpy (nsnbuf, nsname, sizeof (nsnbuf)); if (init (nsnbuf) == FALSE) { - set_io (UNIX); + if (fm_initialized) set_io (UNIX); fprintf (stderr, "\nError initializing FreeM.\n"); exit (1); - } + } + else { + fm_initialized = TRUE; + } direct_mode = FALSE; @@ -703,10 +706,6 @@ int main (int argc, char **argv, char ** /* isolate the path from the routine file */ strncpy (cli_rtn_path, argv[optind], strrchr (argv[optind], '/') - argv[optind]); -/* set_io (UNIX); - printf ("cli_rtn_name = '%s' cli_rtn_path = '%s'\n", cli_rtn_name, cli_rtn_path); - set_io (MUMPS); -*/ } /* do we have a file extension? */ @@ -724,29 +723,30 @@ int main (int argc, char **argv, char ** } /* make this the startup routine */ - snprintf (startuprou, 256, "^%s\201", cli_rtn_name); + snprintf (startuprou, sizeof (startuprou) - 1, "^%s\201", cli_rtn_name); /* re-work the namespace config to search for the routine in the discovered path */ if (cli_rtn_name[0] == '%') { - snprintf (rou0plib, 256, "%s\201", cli_rtn_path); - snprintf (rou1plib, 256, "%s\201", cli_rtn_path); + snprintf (rou0plib, sizeof (rou0plib) - 1, "%s\201", cli_rtn_path); + snprintf (rou1plib, sizeof (rou1plib) - 1, "%s\201", cli_rtn_path); } else { - snprintf (rou0path, 256, "%s\201", cli_rtn_path); - snprintf (rou1path, 256, "%s\201", cli_rtn_path); + snprintf (rou0path, sizeof (rou0path) - 1, "%s\201", cli_rtn_path); + snprintf (rou1path, sizeof (rou1path) - 1, "%s\201", cli_rtn_path); } } - + if (!file_exists (config_file)) { - set_io (UNIX); + if (fm_initialized == TRUE) set_io (UNIX); + fprintf (stderr, "\nFreeM has not been configured. Please run 'fmadm configure'.\n\n\n\n"); exit (2); @@ -755,16 +755,17 @@ int main (int argc, char **argv, char ** if (!skip_init) { /* initialize FreeM environment */ - strncpy (nsnbuf, nsname, 255); - if (init (nsnbuf) == FALSE) { - + strncpy (nsnbuf, nsname, sizeof (nsnbuf)); + if (init (nsnbuf) == FALSE) { set_io (UNIX); fprintf (stderr, "\nError initializing FreeM.\n"); exit (1); - } - } + else { + fm_initialized = TRUE; + } + } if (first_process == TRUE) { @@ -772,16 +773,14 @@ int main (int argc, char **argv, char ** pid_t stop_requester; if (run_daemon == FALSE) { - fprintf (stderr, "freem: re-run with --daemon or -d command-line flags\r\n"); - cleanup (); - exit (1); + logprintf (FM_LOG_FATAL, "freem: re-run with --daemon or -d command-line flags"); } stcpy (verstr, FREEM_VERSION_STR); stcnv_m2c (verstr); fprintf (stderr, "Coherent Logic Development FreeM version %s\r\n", verstr); - fprintf (stderr, "freem: shared memory for environment %s initialized (%ld bytes of shared memory @ '%p')\r\nfreem: system ready\r\n", shm_env, (long) shm_init_size, shm_config->dta); + logprintf (FM_LOG_INFO, "freem: shared memory for environment %s initialized (%ld bytes of shared memory @ '%p')", shm_env, (long) shm_init_size, shm_config->dta); for (;;) { @@ -792,8 +791,7 @@ int main (int argc, char **argv, char ** job_slot_t *slot; - fprintf (stderr, "freem: entering maintenance mode\r\n"); - m_log (1, "freem: entering maintenance mode"); + logprintf (FM_LOG_WARNING, "environment: entering maintenance mode"); for (slot = shm_config->hdr->jobtab_head; slot != NULL; slot = slot->next) { @@ -812,29 +810,29 @@ int main (int argc, char **argv, char ** connected_jobs = job_count (); - fprintf (stderr, "freem: STOP requested by pid %d\r\n", stop_requester); - fprintf (stderr, "freem: there are %d job(s) connected to this environment\r\n", connected_jobs); + logprintf (FM_LOG_INFO, "environment: STOP requested by pid %ld", stop_requester); + logprintf (FM_LOG_INFO, "environment: there are %d job(s) connected to this environment", connected_jobs); if (connected_jobs > 1) { - fprintf (stderr, "freem: asking non-daemon job(s) to disconnect and halt...\r\n"); + logprintf (FM_LOG_INFO, "environment: asking non-daemon job(s) to disconnect and halt..."); job_request_all_stop (); - fprintf (stderr, "freem: waiting 5 seconds for job(s) to disconnect...\r\n"); + logprintf (FM_LOG_INFO, "environment: waiting 5 seconds for job(s) to disconnect..."); sleep (5); connected_jobs = job_count (); - if (connected_jobs > 1) { - fprintf (stderr, "freem: sending SIGTERM to %d job(s)...\r\n", connected_jobs); + if (connected_jobs > 1) { + logprintf (FM_LOG_INFO, "environment: sending SIGTERM to %d job(s)...", connected_jobs); job_signal_all (SIGTERM); - fprintf (stderr, "freem: waiting 5 seconds for job(s) to disconnect...\r\n"); + logprintf (FM_LOG_INFO, "environment: waiting 5 seconds for job(s) to disconnect..."); sleep (5); } connected_jobs = job_count (); if (connected_jobs > 1) { - fprintf (stderr, "freem: sending SIGKILL to %d job(s)...\r\n", connected_jobs); + logprintf (FM_LOG_INFO, "environment: sending SIGKILL to %d job(s)...", connected_jobs); job_signal_all (SIGKILL); } @@ -843,8 +841,9 @@ int main (int argc, char **argv, char ** } - fprintf (stderr, "freem: terminating\r\n"); + logprintf (FM_LOG_INFO, "freem: terminating"); cleanup (); + exit (0); } @@ -862,24 +861,16 @@ int main (int argc, char **argv, char ** #if !defined(_AIX) - if(import_env == TRUE) { - + if (import_env == TRUE) { int i_maxlen = 255; - for(env = envp; *env != 0; env++) { - - namelen = 0; - vallen = 0; - - varname = strtok(*env, "="); - varval = strtok(NULL, "="); - - if(varval != NULL) { - namelen = strlen (varname); - vallen = strlen (varval); + for (env = envp; *env != 0; env++) { + varname = strtok (*env, "="); + varval = strtok (NULL, "="); + if (varval != NULL) { snprintf (symname, i_maxlen, "ENV.%s\201\201", varname); - strncpy (symval, varval, i_maxlen); + strncpy (symval, varval, i_maxlen - 1); stcnv_c2m (symval); @@ -898,10 +889,10 @@ int main (int argc, char **argv, char ** stcpy (verstr, FREEM_VERSION_STR); stcnv_m2c (verstr); - snprintf (version, 255, "\r\nCoherent Logic Development FreeM version %s [DIALECT: %s%s]\r\n\201", verstr, m_dialect, (restricted_mode == TRUE ? "/RESTRICTED" : "")); + snprintf (version, sizeof (version) - 1, "\r\nCoherent Logic Development FreeM version %s [DIALECT: %s%s]\r\n\201", verstr, m_dialect, (restricted_mode == TRUE ? "/RESTRICTED" : "")); write_m (version); - snprintf (version, 255, "Copyright (C) 2014, 2020, 2021, 2023, 2025 Coherent Logic Development LLC\r\n\r\n\201"); + snprintf (version, sizeof (version) - 1, "Copyright (C) 2014, 2020, 2021, 2023, 2025 Coherent Logic Development LLC\r\n\r\n\201"); write_m (version); /* @@ -918,7 +909,7 @@ int main (int argc, char **argv, char ** if (dx_mode) { char k_buf[512]; - snprintf (k_buf, 512 - 1, "%%TMPINITMCODE\201\201"); + snprintf (k_buf, sizeof (k_buf) - 1, "%%TMPINITMCODE\201\201"); symtab (set_sym, k_buf, dx_mcode); const_define (k_buf, dx_mcode); } @@ -926,7 +917,7 @@ int main (int argc, char **argv, char ** if (routine_mode) { char k_buf[512]; - snprintf (k_buf, 512 - 1, "%%TMPINITROUTINE\201\201"); + snprintf (k_buf, sizeof (k_buf) - 1, "%%TMPINITROUTINE\201\201"); symtab (set_sym, k_buf, startup_routine); const_define (k_buf, startup_routine); } @@ -957,7 +948,6 @@ void freem_usage(void) fprintf (stdout, "\t-x , --execute=\n\t\texecute M code on startup\n\n"); fprintf (stdout, "\t-d, --daemon\n\t\trun the FreeM daemon (one and only one FreeM daemon must always be running)\n\n"); fprintf (stdout, "\t-k, --nofork\n\t\trun the FreeM daemon in foreground (requires --daemon)\n\n"); - fprintf (stdout, "\t-p , --pidfile=\n\t\tuse to record the PID of the FreeM daemon\n\n\n"); fprintf (stdout, "\t-S , --shmsize=\n\t\tsets the size of the shared memory segment where FreeM stores the job table, lock table, and IPC table.\n"); #else fprintf (stdout, "\t-h\n\t\tdisplays this help message\n\n"); @@ -972,7 +962,6 @@ void freem_usage(void) fprintf (stdout, "\t-x \n\t\texecute M code on startup\n\n"); fprintf (stdout, "\t-d\n\t\trun the FreeM daemon (one and only one FreeM daemon must always be running)\n\n"); fprintf (stdout, "\t-k\n\t\trun the FreeM daemon in foreground (requires --daemon)\n\n"); - fprintf (stdout, "\t-p \n\t\tuse to record the PID of the FreeM daemon\n\n\n"); fprintf (stdout, "\t-S \n\t\tsets the size of the shared memory segment where FreeM stores the job table, lock table, and IPC table.\n"); #endif fprintf (stdout, "\t\t - Each concurrent job takes %d bytes (1 page) of shared memory\n", PG_SIZE);