--- freem/src/fmadm.c	2025/03/24 19:19:42	1.9
+++ freem/src/fmadm.c	2025/04/03 01:41:02	1.29
@@ -1,5 +1,5 @@
 /*
- *   $Id: fmadm.c,v 1.9 2025/03/24 19:19:42 snw Exp $
+ *   $Id: fmadm.c,v 1.29 2025/04/03 01:41:02 snw Exp $
  *    FreeM Administration Tool
  *
  *  
@@ -24,6 +24,66 @@
  *   along with FreeM.  If not, see .
  *
  *   $Log: fmadm.c,v $
+ *   Revision 1.29  2025/04/03 01:41:02  snw
+ *   New features frozen; prepare 0.63.0-rc1
+ *
+ *   Revision 1.28  2025/04/02 19:59:38  snw
+ *   Automatically modify env.conf from fmadm reconfigure
+ *
+ *   Revision 1.27  2025/04/02 15:36:25  snw
+ *   Do extensive result checking for environment stop/start/restart in fmadm
+ *
+ *   Revision 1.26  2025/04/02 14:37:57  snw
+ *   Improve environment control parts of fmadm
+ *
+ *   Revision 1.25  2025/04/02 04:50:49  snw
+ *   Allow vendor routines to be upgraded
+ *
+ *   Revision 1.24  2025/04/02 03:02:42  snw
+ *   Stop requiring users to pass -e to fmadm when -u or -g are passed
+ *
+ *   Revision 1.23  2025/04/02 02:16:27  snw
+ *   Add fmadm status environment command and move journals to a better location
+ *
+ *   Revision 1.22  2025/04/01 23:21:45  snw
+ *   fmadm commands for stopping, starting, and restarting environments now functional
+ *
+ *   Revision 1.21  2025/04/01 20:11:46  snw
+ *   Further work on fmadm
+ *
+ *   Revision 1.20  2025/04/01 16:37:12  snw
+ *   Configure DEFAULT environment the same as others, and set permissions/ownership directly in fmadm configure. Add env.conf file as a centralized configuration listing all environments.
+ *
+ *   Revision 1.19  2025/04/01 14:32:11  snw
+ *   Begin work on environment and namespace reorg
+ *
+ *   Revision 1.18  2025/03/31 16:33:56  snw
+ *   Work on fmadm edit global
+ *
+ *   Revision 1.17  2025/03/30 01:36:58  snw
+ *   Make it easier to bring back fma_gedit, fix double-free in global handler, limit $CHAR to 7-bit ASCII
+ *
+ *   Revision 1.16  2025/03/24 20:59:58  snw
+ *   Try using DosCopy API instead of built-in cp function on OS/2
+ *
+ *   Revision 1.15  2025/03/24 20:58:05  snw
+ *   Try using DosCopy API instead of built-in cp function on OS/2
+ *
+ *   Revision 1.14  2025/03/24 20:57:06  snw
+ *   Try using DosCopy API instead of built-in cp function on OS/2
+ *
+ *   Revision 1.13  2025/03/24 20:15:09  snw
+ *   Set file permissions on freemd.exe on OS/2 in fmadm configure
+ *
+ *   Revision 1.12  2025/03/24 20:13:34  snw
+ *   Set file permissions on freemd.exe on OS/2 in fmadm configure
+ *
+ *   Revision 1.11  2025/03/24 19:25:48  snw
+ *   Make fmadm configure copy freem.exe to freemd.exe for daemon operation on OS/2 systems
+ *
+ *   Revision 1.10  2025/03/24 19:22:16  snw
+ *   Make fmadm configure copy freem.exe to freemd.exe for daemon operation on OS/2 systems
+ *
  *   Revision 1.9  2025/03/24 19:19:42  snw
  *   Make fmadm configure copy freem.exe to freemd.exe for daemon operation on OS/2 systems
  *
@@ -40,6 +100,8 @@
 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -53,6 +115,10 @@
 #include "namespace.h"
 #include "fs.h"
 
+#if defined(__OS2__)
+# include 
+#endif
+
 #ifdef HAVE_LIBREADLINE
 #  if defined(HAVE_READLINE_READLINE_H)
 #    include 
@@ -108,13 +174,21 @@ short fma_explicit_environment = FALSE;
 char obj_str[STRLEN];
 
 extern char config_file[4096];
+extern char env_config_file[4096];
+extern char env_user[255];
+extern char env_group[255];
+extern char env_enabled[10];
 
 int fm_shell(void);
 void fm_checkperms(void);
 void fm_reconfigure(void);
 void fm_configure(void);
+int fm_daemonctl (short action, short object, int optc, char **options);
 void fm_write (FILE *file, char *buf);
 int fma_jobs_remove (int optc, char **opts);
+void set_permissions(char *path, char *user, char *grp, int mode);
+int fm_environment_running (char *env);
+extern int read_profile_string(char *file, char *section, char *key, char *value);
 
 int main (int argc, char **argv)
 {
@@ -134,6 +208,7 @@ int main (int argc, char **argv)
     short got_action = FALSE;
     short got_object = FALSE;
 
+    strcpy (env_enabled, "true");
 
     /* snprintf (config_file, 4096, "%s/freem.conf", SYSCONFDIR); */
 
@@ -162,6 +237,41 @@ int main (int argc, char **argv)
         if (argv[i][0] == '-') {
                         
             switch (argv[i][1]) {
+
+                case 'u':
+                    if (argv[i][2] != '=') {
+                        fprintf (stderr, "fmadm:  missing equals sign in flag -%c\n", argv[i][1]);
+                        fmadm_usage ();
+                        exit (1);
+                    }
+
+                    k = 0;
+                    
+                    for (j = 3; j < strlen (argv[i]); j++) {
+                        env_user[k++] = argv[i][j];
+                    }
+                    
+                    base_arg++;
+                    
+                    break;
+
+                case 'g':
+                    if (argv[i][2] != '=') {
+                        fprintf (stderr, "fmadm:  missing equals sign in flag -%c\n", argv[i][1]);
+                        fmadm_usage ();
+                        exit (1);
+                    }
+
+                    k = 0;
+                    
+                    for (j = 3; j < strlen (argv[i]); j++) {
+                        env_group[k++] = argv[i][j];
+                    }
+                    
+                    base_arg++;
+                    
+                    break;
+                    
                 
                 case 'e':
                     if (argv[i][2] != '=') {
@@ -175,11 +285,41 @@ int main (int argc, char **argv)
                     for (j = 3; j < strlen (argv[i]); j++) {
                         fma_environment[k++] = argv[i][j];
                     }
+
+                    if (strcmp (fma_environment, "all") == 0 ) {
+                        fprintf (stderr, "fmadm:  'all' is an invalid environment name\n");
+                        exit (1);
+                    }
                     
                     fma_explicit_environment = TRUE;
                     base_arg++;
                     
                     break;
+
+                case 'E':
+                    if (argv[i][2] != '=') {
+                        fprintf (stderr, "fmadm:  missing equals sign in flag -%c\n", argv[i][1]);
+                        fmadm_usage ();
+                        exit (1);
+                    }
+
+                    k = 0;
+                    
+                    for (j = 3; j < strlen (argv[i]); j++) {
+                        env_enabled[k++] = argv[i][j];
+                    }
+                    env_enabled[k] = '\0';
+
+                    if ((strcmp (env_enabled, "true") != 0) && (strcmp (env_enabled, "false") != 0)) {
+                        fprintf (stderr, "fmadm:  -E (environment enabled) option must be either 'true' or 'false'\n");
+                        fmadm_usage ();
+                        exit (1);
+                    }
+                    
+                    base_arg++;
+                    
+                    break;
+                    
                     
                 case 'n':
                     if (argv[i][2] != '=') {
@@ -202,18 +342,31 @@ int main (int argc, char **argv)
             }
         }
     }
-
-    if (!fma_explicit_environment) snprintf (fma_environment, 4096, "DEFAULT");
-    if (!fma_explicit_namespace) snprintf (fma_namespace, 4096, "SYSTEM");
     
-    snprintf (config_file, 4096, "%s/freem/%s/freem.conf", SYSCONFDIR, fma_environment);
+    if (obj != OBJ_DAEMON) {
+        if (strlen (env_user) == 0) {
+            snprintf (env_user, 6, "freem");
+        }
+        
+        if (strlen (env_group) == 0) {
+            snprintf (env_group, 6, "freem");
+        }
 
-    /*
+
+        if (!fma_explicit_environment) snprintf (fma_environment, 4096, "DEFAULT");
+        if (!fma_explicit_namespace) snprintf (fma_namespace, 4096, "SYSTEM");
+    
+        snprintf (config_file, 4096, "%s/freem/%s/freem.conf", SYSCONFDIR, fma_environment);
+    }
+    
+    snprintf (env_config_file, 4096, "%s/freem/env.conf", SYSCONFDIR);
+    
+/*
     printf ("action = '%s' object = '%s' environment = '%s' namespace = '%s' config_file = '%s' base_arg = '%d' next argument = '%s'\n", action, obj_str, fma_environment, fma_namespace, config_file, base_arg, argv[base_arg]);
     exit(1);
-    */
+*/
     
-    /* override for fmadm configure */
+    /* override for fmadm configure and daemon stuff */
     if (got_action) {
         if (strcmp (argv[1], "configure") == 0) {
             fm_configure ();
@@ -223,6 +376,27 @@ int main (int argc, char **argv)
             fm_reconfigure ();
             exit (0);
         }
+        else if (strcmp (argv[1], "start") == 0 && strcmp (argv[2], "environment") == 0) {
+            act = ACT_START;
+            obj = OBJ_DAEMON;
+            goto process_args;
+        }
+        else if (strcmp (argv[1], "stop") == 0 && strcmp (argv[2], "environment") == 0) {
+            act = ACT_STOP;
+            obj = OBJ_DAEMON;
+            goto process_args;
+        }
+        else if (strcmp (argv[1], "restart") == 0  && strcmp (argv[2], "environment") == 0) {
+            act = ACT_RESTART;
+            obj = OBJ_DAEMON;
+            goto process_args;
+        }
+        else if (strcmp (argv[1], "status") == 0  && strcmp (argv[2], "environment") == 0) {
+            act = ACT_STATUS;
+            obj = OBJ_DAEMON;
+            goto process_args;
+        }        
+
     }
 
     pid = getpid ();
@@ -233,7 +407,7 @@ int main (int argc, char **argv)
     job_init (TRUE);
 
     fm_sig_init ();
-    
+
     /* go to fmadm shell if no arguments passed */
     if (!got_action && !got_object) return fm_shell ();    
     
@@ -241,74 +415,10 @@ int main (int argc, char **argv)
 	fm_checkperms ();
 	exit (0);
     }
-
-#if 0
-    /* how many args do we have? */
-    switch (argc) {
-        
-        case 3: /* action, object */
-            strncpy (action, argv[1], STRLEN - 1);
-            strncpy (obj_str, argv[2], STRLEN - 1);
-            strncpy (fma_namespace, "SYSTEM", STRLEN - 1);
-
-            optc = argc - 2;
-            
-            fma_explicit_namespace = FALSE;
-            fma_min_args = 1;
-            base_arg = 3;
-            
-            break;
-
-        case 4: /* action, object, namespace */
-
-            strncpy (action, argv[1], STRLEN - 1);
-            strncpy (obj_str, argv[2], STRLEN - 1);
-
-            if (validate_namespace (argv[3]) == TRUE) {
-                strncpy (fma_namespace, argv[3], STRLEN - 1);
-                fma_min_args = 2;
-                fma_explicit_namespace = TRUE;
-                base_arg = 4;
-                optc = argc - 3;
-            }
-            else {
-                strncpy (fma_namespace, "SYSTEM", 10);
-                fma_min_args = 1;
-                fma_explicit_namespace = FALSE;
-                base_arg = 3;
-                optc = argc - 2;
-            }
-
-            break;
-
-        default:
-            if (argc < 4) fmadm_usage();
-
-            /* we don't know what any but the first two args actually mean */
-            strncpy (action, argv[1], STRLEN - 1);
-            strncpy (obj_str, argv[2], STRLEN - 1);
-
-            if (validate_namespace (argv[3]) == TRUE) {
-                strncpy (fma_namespace, argv[3], STRLEN - 1);
-                fma_min_args = 2;
-                fma_explicit_namespace = TRUE;
-                base_arg = 4;
-                optc = argc - 3;
-            }
-            else {
-                strncpy (fma_namespace, "SYSTEM", 10);
-                fma_min_args = 1;
-                fma_explicit_namespace = FALSE;
-                base_arg = 3;
-                optc = argc - 2;
-            }
-
-
-    }
-#endif
     
     set_namespace (fma_namespace, FALSE);
-    
+
+process_args:    
     /* allocate opts array */
     
     /* first dimension */
@@ -331,7 +441,8 @@ int main (int argc, char **argv)
 
     j = 1;
     for (i = base_arg; i < argc; i++) {
-        if (i > FMA_MAXARGS) return fmadm_usage(); /* bail if we're going to overrun the array */
+        if (i > FMA_MAXARGS) return fmadm_usage();        
+        /* bail if we're going to overrun the array */
         strncpy (opts[j++], argv[i], STRLEN - 1);
     }
     
@@ -347,18 +458,24 @@ int main (int argc, char **argv)
     else if (strncmp (action, "backup", STRLEN - 1) == 0) act = ACT_BACKUP;
     else if (strncmp (action, "restore", STRLEN - 1) == 0) act = ACT_RESTORE;
     else if (strncmp (action, "migrate", STRLEN - 1) == 0) act = ACT_MIGRATE;
-    else if (strncmp (action, "edit", STRLEN -1) == 0) act = ACT_EDIT;
+    else if (strncmp (action, "edit", STRLEN - 1) == 0) act = ACT_EDIT;
+    else if (strncmp (action, "start", STRLEN - 1) == 0) act = ACT_START;
+    else if (strncmp (action, "stop", STRLEN - 1) == 0) act = ACT_STOP;
+    else if (strncmp (action, "restart", STRLEN - 1) == 0) act = ACT_RESTART;
+    else if (strncmp (action, "status", STRLEN - 1) == 0) act = ACT_STATUS;
     else return fmadm_usage();
 
     if (strncmp (obj_str, "lock", STRLEN - 1) == 0) obj = OBJ_LOCK;
-    else if (strncmp (obj_str, "zallocate", STRLEN - 1) == 0) obj = OBJ_ZALLOC;
     else if (strncmp (obj_str, "journal", STRLEN - 1) == 0) obj = OBJ_JOURNAL;
     else if (strncmp (obj_str, "namespace", STRLEN - 1) == 0) obj = OBJ_NAMESPACE;
     else if (strncmp (obj_str, "global", STRLEN - 1) == 0) obj = OBJ_GLOBAL;
     else if (strncmp (obj_str, "routine", STRLEN - 1) == 0) obj = OBJ_ROUTINE;
     else if (strncmp (obj_str, "job", STRLEN - 1) == 0) obj = OBJ_JOB;
+    else if (strncmp (obj_str, "environment", STRLEN - 1) == 0) obj = OBJ_DAEMON;
     else return fmadm_usage();
 
+    if (act > ACT_EDIT) goto act_switch;    
+    
     if (get_conf (fma_namespace, "routines_path", fma_routine_path) == FALSE) {
         fprintf (stderr, "fmadm:  cannot determine routine path for namespace %s\n", fma_namespace);
         return 1;
@@ -394,6 +511,7 @@ int main (int argc, char **argv)
     stcnv_c2m (glopath);
 
 
+act_switch:
     switch (act) {
 
         
@@ -448,6 +566,11 @@ int main (int argc, char **argv)
         case ACT_EDIT:
             fmadm_exit (fm_edit (obj, optc, opts));
 
+        case ACT_START:
+        case ACT_STOP:
+        case ACT_RESTART:
+        case ACT_STATUS:
+            fmadm_exit (fm_daemonctl (act, obj, optc, opts));
 
         default:
             return fmadm_usage();
@@ -600,7 +723,6 @@ int fm_shell (void)
             strcpy (obj_str, args[0]);
         
             if (strncmp (obj_str, "lock", STRLEN - 1) == 0) obj = OBJ_LOCK;
-            else if (strncmp (obj_str, "zallocate", STRLEN - 1) == 0) obj = OBJ_ZALLOC;
             else if (strncmp (obj_str, "journal", STRLEN - 1) == 0) obj = OBJ_JOURNAL;
             else if (strncmp (obj_str, "namespace", STRLEN - 1) == 0) obj = OBJ_NAMESPACE;
             else if (strncmp (obj_str, "global", STRLEN - 1) == 0) obj = OBJ_GLOBAL;
@@ -793,17 +915,18 @@ void fmadm_exit (int retval)
 int fmadm_usage (void)
 {
 
-    fprintf (stdout, "\nusage:  fmadm