--- freem/src/mumps.c	2025/04/01 23:21:45	1.11
+++ freem/src/mumps.c	2025/04/04 19:43:18	1.16
@@ -1,5 +1,5 @@
 /*
- *   $Id: mumps.c,v 1.11 2025/04/01 23:21:45 snw Exp $
+ *   $Id: mumps.c,v 1.16 2025/04/04 19:43:18 snw Exp $
  *    main module of freem
  *
  *  
@@ -24,6 +24,21 @@
  *   along with FreeM.  If not, see <https://www.gnu.org/licenses/>.
  *
  *   $Log: mumps.c,v $
+ *   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
  *
@@ -53,6 +68,7 @@
  * SPDX-License-Identifier: AGPL-3.0-or-later
  **/
 
+#define _GNU_SOURCE
 #include <stdlib.h>
 #include <stddef.h>
 #include "mpsdef.h"
@@ -109,6 +125,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;
@@ -162,6 +180,8 @@ int main (int argc, char **argv, char **
     char *cli_rtn_file;
     char cli_rtn_name[256];
 
+    char env_ena[25];
+    
     routine_mode = FALSE;
     strcpy (m_dialect, "FREEM");
     
@@ -191,7 +211,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 ();
@@ -304,18 +324,7 @@ int main (int argc, char **argv, char **
 
             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;                
 
         } 
 
@@ -327,7 +336,7 @@ int main (int argc, char **argv, char **
         extern char *optarg;
         extern int optind, optopt;
 
-        while ((c = getopt (argc, argv, "hsfiqRr:n:e:vx:dkS:u:g:")) != -1) {
+        while ((c = getopt (argc, argv, "hsfiqRr:n:e:vx:dkS:")) != -1) {
 
 	    if (c == '?') freem_usage ();
 	    
@@ -435,17 +444,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;
-
-                    
             } 
         }
     }
@@ -459,34 +457,66 @@ int main (int argc, char **argv, char **
 #endif
     
     snprintf (config_file, 4096, "%s/freem/%s/freem.conf", SYSCONFDIR, shm_env);
+    snprintf (env_config_file, 4096, "%s/freem/env.conf", SYSCONFDIR);    
     
-    if (run_daemon == TRUE && geteuid() == 0) {
+    if (!file_exists (env_config_file)) {
+        fprintf (stderr, "freem:  environment catalog does not exist; may need to run fmadm configure\n");
+        exit (1);
+    }
 
-        if (custom_group) {
-            d_grp = getgrnam (d_groupname);
+    if (!file_exists (config_file)) {
+        fprintf (stderr, "freem:  configuration file for %s does not exist; may need to run fmadm configure\n", shm_env);
+        exit (1);
+    }
 
-            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) {
+        fprintf (stderr, "freem:  could not determine owning user for environment %s\n", shm_env);
+        exit (1);
+    }
 
-        if (custom_user) {
-            d_user = getpwnam (d_username);
+    if (read_profile_string (env_config_file, shm_env, "group", d_groupname) == FALSE) {
+        fprintf (stderr, "freem:  could not determine owning group for environment %s\n", shm_env);
+        exit (1);
+    }
 
-            if (d_user == NULL) {
-                fprintf (stderr, "freem:  invalid user '%s'\n", d_username);
-                exit (1);
-            }
-            
-            d_uid = d_user->pw_uid;
-        }
-        else {
-            d_uid = 0;
-        }
+    if (read_profile_string (env_config_file, shm_env, "enabled", env_ena) == FALSE) {
+        fprintf (stderr, "freem:  could not discover enabled state for environment %s\n", shm_env);
+        exit (1);
+    }
+
+    if (strcmp (env_ena, "true") != 0) {
+        fprintf (stderr, "freem:  environment %s is administratively disabled\n", shm_env);
+        exit (1);
+    }    
+
+    d_grp = getgrnam (d_groupname);        
+    if (d_grp == NULL) {
+        fprintf (stderr, "freem:  invalid group '%s'\n", d_groupname);
+        exit (1);
+    }            
+    d_gid = d_grp->gr_gid;
+        
+    d_user = getpwnam (d_username);
+    if (d_user == NULL) {
+        fprintf (stderr, "freem:  invalid user '%s'\n", d_username);
+        exit (1);
+    }            
+    d_uid = d_user->pw_uid;
+
+    
+#if defined(__linux__)    
+    if (run_daemon == FALSE && group_member (d_gid) == 0) {
+        fprintf (stderr, "freem:  you must be a member of the %s group to use environment %s\n", d_groupname, shm_env);
+        exit (1);
+    }
         
+#endif    
+    
+    if (run_daemon == TRUE) {
+        if (geteuid () != 0 && nofork == FALSE) {
+            fprintf (stderr, "freem:  forking daemon must be run as root\n");
+            exit (1);
+        }                
     }
     
     if ((nofork == TRUE) && (run_daemon == FALSE)) {
@@ -592,6 +622,7 @@ int main (int argc, char **argv, char **
             errsav = errno;
             
             if (pid_fd < 0) {
+                fprintf (stderr, "freem:  could not open PID file %s [%s]\n", pid_file_path, strerror (errsav));
                 m_log (1, "freem:  could not open PID file");
                 m_log (1, strerror (errsav));
                 exit (1);
@@ -599,6 +630,7 @@ int main (int argc, char **argv, char **
 
             if (lockf (pid_fd, F_TLOCK, 0) < 0) {
                 errsav = errno;
+                fprintf (stderr, "freem:  could not lock PID file [%s]\n", strerror (errsav));
                 m_log (1, "freem: could not lock PID file - perhaps already running?");
                 m_log (1, strerror (errsav));
                 exit (1);
@@ -639,12 +671,15 @@ int main (int argc, char **argv, char **
 	strncpy (nsnbuf, nsname, 255);    
 	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;
@@ -671,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? */
@@ -711,10 +742,11 @@ int main (int argc, char **argv, char **
 
     }
 
-
+    
     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);
@@ -724,14 +756,15 @@ int main (int argc, char **argv, char **
     if (!skip_init) {
 	/* initialize FreeM environment */
 	strncpy (nsnbuf, nsname, 255);    
-	if (init (nsnbuf) == FALSE) {
-	    
+	if (init (nsnbuf) == FALSE) {	    
 	    set_io (UNIX);
 	    fprintf (stderr, "\nError initializing FreeM.\n");
 
 	    exit (1);
-
 	}
+        else {
+            fm_initialized = TRUE;
+        }
     }
 
     if (first_process == TRUE) {
@@ -940,7 +973,6 @@ void freem_usage(void)
     fprintf (stdout, "\t-x <MCODE>\n\t\texecute M code <MCODE> 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 <PIDFILE>\n\t\tuse <PIDFILE> to record the PID of the FreeM daemon\n\n\n");
     fprintf (stdout, "\t-S <BYTES>\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);