--- freem/src/fmadm.c	2025/04/01 20:11:46	1.21
+++ freem/src/fmadm.c	2025/04/02 19:59:38	1.28
@@ -1,5 +1,5 @@
 /*
- *   $Id: fmadm.c,v 1.21 2025/04/01 20:11:46 snw Exp $
+ *   $Id: fmadm.c,v 1.28 2025/04/02 19:59:38 snw Exp $
  *    FreeM Administration Tool
  *
  *  
@@ -24,6 +24,27 @@
  *   along with FreeM.  If not, see <https://www.gnu.org/licenses/>.
  *
  *   $Log: fmadm.c,v $
+ *   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
  *
@@ -162,6 +183,7 @@ int fm_daemonctl (short action, short ob
 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)
@@ -224,7 +246,6 @@ int main (int argc, char **argv)
                         env_user[k++] = argv[i][j];
                     }
                     
-                    fma_explicit_environment = TRUE;
                     base_arg++;
                     
                     break;
@@ -242,7 +263,6 @@ int main (int argc, char **argv)
                         env_group[k++] = argv[i][j];
                     }
                     
-                    fma_explicit_environment = TRUE;
                     base_arg++;
                     
                     break;
@@ -292,7 +312,7 @@ int main (int argc, char **argv)
             }
         }
     }
-
+    
     if (obj != OBJ_DAEMON) {
         if (strlen (env_user) == 0) {
             snprintf (env_user, 6, "freem");
@@ -311,10 +331,10 @@ int main (int argc, char **argv)
     
     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 and daemon stuff */
     if (got_action) {
@@ -329,18 +349,24 @@ int main (int argc, char **argv)
         else if (strcmp (argv[1], "start") == 0 && strcmp (argv[2], "environment") == 0) {
             act = ACT_START;
             obj = OBJ_DAEMON;
-            goto act_switch;
+            goto process_args;
         }
         else if (strcmp (argv[1], "stop") == 0 && strcmp (argv[2], "environment") == 0) {
             act = ACT_STOP;
             obj = OBJ_DAEMON;
-            goto act_switch;
+            goto process_args;
         }
         else if (strcmp (argv[1], "restart") == 0  && strcmp (argv[2], "environment") == 0) {
             act = ACT_RESTART;
             obj = OBJ_DAEMON;
-            goto act_switch;
+            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 ();
@@ -361,7 +387,8 @@ int main (int argc, char **argv)
     }
     
     set_namespace (fma_namespace, FALSE);
-    
+
+process_args:    
     /* allocate opts array */
     
     /* first dimension */
@@ -384,7 +411,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);
     }
     
@@ -404,10 +432,10 @@ int main (int argc, char **argv)
     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;
@@ -511,6 +539,7 @@ act_switch:
         case ACT_START:
         case ACT_STOP:
         case ACT_RESTART:
+        case ACT_STATUS:
             fmadm_exit (fm_daemonctl (act, obj, optc, opts));
 
         default:
@@ -664,7 +693,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;
@@ -868,7 +896,7 @@ int fmadm_usage (void)
     fprintf (stdout, "            stop, restart\n\n");
 
     fprintf (stdout, "        <object> can be one of:\n");
-    fprintf (stdout, "            lock, zallocate, journal, namespace, global, routine, job,\n");
+    fprintf (stdout, "            lock, journal, namespace, global, routine, job,\n");
     fprintf (stdout, "            environment\n\n");
 
     fprintf (stdout, "    Not all actions are valid for all objects. Please see the FreeM manual\n");
@@ -1104,6 +1132,135 @@ int fm_edit (short object, int optc, cha
 
 } /* fm_edit() */
 
+long fm_get_pid (char *env)
+{
+    char pid_file[4096];
+    char tmp_pid[255];
+    long res;
+    
+    FILE *fp;
+
+    snprintf (pid_file, 4095, "%s/freem/run/%s.pid", LOCALSTATEDIR, env);
+
+    if ((fp = fopen (pid_file, "r")) != NULL) {
+        if (fgets (tmp_pid, 255, fp)) {
+            fclose (fp);
+            return atol (tmp_pid);            
+        }
+        else {
+            fclose (fp);
+            return -1;
+        }        
+    }
+    else {
+        return -1;
+    }            
+}
+
+int fm_validate_environment (char *env)
+{
+    FILE *fp;
+    char line[255];
+    char chkline[255];
+
+    snprintf (chkline, 254, "[%s]\n", env);
+    
+    if ((fp = fopen (env_config_file, "r")) == NULL) {
+        fprintf (stderr, "fmadm:  could not open %s [%s]\n", env_config_file, strerror (errno));
+        return FALSE;
+    }
+
+    while (fgets (line, 254, fp)) {
+        if (strncmp (line, chkline, 254) == 0) {
+            fclose (fp);
+            return TRUE;
+        }
+    }
+
+    fclose (fp);
+    return FALSE;
+}
+
+int fm_start_environment (char *env, char *e_user, char *e_grp)
+{
+    char basecmd[255];
+    char cmd[4096];    
+
+    if (fm_environment_running (env) == TRUE) {
+        return TRUE;
+    }
+    
+#if !defined(__OS2__)
+    snprintf (basecmd, 254, "%s/bin/freem", PREFIX);
+#else
+    snprintf (basecmd, 254, "%s/bin/freemd.exe", PREFIX);
+#endif
+
+#if !defined(__OS2__)                    
+    snprintf (cmd, 4095, "%s -d -e %s -u %s -g %s", basecmd, env, e_user, e_grp);
+#else
+    sprintf (cmd, 4095, "%s -d -k -e %s -u %s -g %s", basecmd, env, e_user, e_grp);
+#endif
+
+    system (cmd);
+
+    sleep (1);
+    
+    return (fm_environment_running (env));
+}
+
+int fm_stop_environment (char *env)
+{
+    long epid;
+
+    epid = fm_get_pid (env);
+    if (epid > -1) {
+        kill (epid, SIGINT);
+        sleep (5);
+
+        if (fm_environment_running (env) == FALSE) {
+            return TRUE;
+        }
+        else {
+            kill (epid, SIGTERM);
+            sleep (5);
+            if (fm_environment_running (env) == FALSE) {
+                return TRUE;
+            }
+            else {
+                kill (epid, SIGKILL);
+                sleep (5);
+                if (fm_environment_running (env) == FALSE) {
+                    return TRUE;
+                }
+                else {
+                    return FALSE;
+                }
+            }
+        }
+    }
+    else {
+        return FALSE;
+    }   
+}
+
+int fm_environment_running (char *env)
+{       
+    long epid;
+    int result;
+    
+    epid = fm_get_pid (env);
+
+    if (epid == -1) {
+        return FALSE;
+    }
+    else {
+        result = kill (epid, 0);
+
+        return ((result == 0) ? TRUE : FALSE);
+    }
+}
+
 int fm_daemonctl (short action, short object, int optc, char **options)
 {
     FILE *ef;
@@ -1112,20 +1269,14 @@ int fm_daemonctl (short action, short ob
     char line[255];
     char tmps[255];
     char *cur_env;
-    char cmd[4096];
-    char verb[20];
+    char verb[40];
     char e_user[255];
     char e_grp[255];
     char e_ena[10];
-    char basecmd[255];    
     char *savptr;
     int result;
-
-#if !defined(__OS2__)
-    snprintf (basecmd, 254, "%s/bin/freem", PREFIX);
-#else
-    snprintf (basecmd, 254, "%s/bin/freemd.exe", PREFIX);
-#endif
+    long epid;
+   
     
     switch (action) {
         case ACT_START:
@@ -1137,11 +1288,17 @@ int fm_daemonctl (short action, short ob
         case ACT_RESTART:
             sprintf (verb, "restarting");
             break;
+        case ACT_STATUS:
+            sprintf (verb, "checking status of");
+            break;
     }
     
     if (optc) {
         /* environment list specified as command-line argument */
-        envlist = options[0];
+        envlist = (char *) malloc (sizeof (char) * BIGSTR);
+        NULLPTRCHK(envlist,"fm_daemonctl");
+
+        strcpy (envlist, options[1]);
     }
     else {
         /* no environment specified; do 'action' for all environments */
@@ -1166,6 +1323,12 @@ int fm_daemonctl (short action, short ob
     savptr = envlist;
     cur_env = strtok_r (envlist, ",", &savptr);
     do {
+        
+        if (fm_validate_environment (cur_env) == FALSE) {
+            fprintf (stderr, "fmadm:  %s is not a valid environment\n", cur_env);
+            continue;
+        }
+
         result = read_profile_string (env_config_file, cur_env, "enabled", e_ena);        
         if (result == FALSE || strcmp (e_ena, "true") == 0) {
 
@@ -1177,24 +1340,65 @@ int fm_daemonctl (short action, short ob
             if (result == FALSE) {
                 strcpy (e_grp, "freem");
             }
-            
-            printf ("fmadm:  %s environment %s\n", verb, cur_env);
 
             switch (action) {
                 case ACT_START:
-#if !defined(__OS2__)                    
-                    snprintf (cmd, 4095, "%s -d -e %s -u %s -g %s", basecmd, cur_env, e_user, e_grp);
-#else
-                    sprintf (cmd, 4095, "%s -d -k -e %s -u %s -g %s", basecmd, cur_env, e_user, e_grp);
-#endif                    
-                    break;
                 case ACT_STOP:
                 case ACT_RESTART:
-                    printf ("fmadm:  stop and restart not yet implemented\n");
+                    fprintf (stderr, "fmadm:  %s environment %s... ", verb, cur_env);
+                    break;
+                case ACT_STATUS:
+                    fprintf (stderr, "fmadm:  %s environment %s\n", verb, cur_env);
                     break;
             }
 
-            system (cmd);
+            switch (action) {
+                
+                case ACT_START:
+                    result = fm_start_environment (cur_env, e_user, e_grp);
+                    if (result == TRUE) {
+                        fprintf (stderr, "[OK]\n");
+                    }
+                    else {
+                        fprintf (stderr, "[FAIL]\n");
+                    }
+                    break;
+
+                case ACT_STOP:
+                    result = fm_stop_environment (cur_env);
+                    if (result == TRUE) {
+                        fprintf (stderr, "[OK]\n");
+                    }
+                    else {
+                        fprintf (stderr, "[FAIL]\n");
+                    }                    
+                    break;
+
+                case ACT_RESTART:
+                    if (fm_stop_environment (cur_env) == TRUE) {
+                        result = fm_start_environment (cur_env, e_user, e_grp);
+                        if (result == TRUE) {
+                            fprintf (stderr, "[OK]\n");
+                        }
+                        else {
+                            fprintf (stderr, "[FAIL]\n");
+                        }                        
+                    }
+                    else {
+                        fprintf (stderr, "[FAIL]\n");
+                    }                       
+
+                    break;
+                    
+                case ACT_STATUS:
+                    epid = fm_get_pid (cur_env);
+                    if (epid > -1) {
+                        fprintf (stderr, " - %s environment daemon running as pid %d\n", cur_env, epid);
+                    }
+                    else {
+                        fprintf (stderr, " - %s environment daemon does not appear to be running\n", cur_env);
+                    }
+            }            
         }
         else {
             printf ("fmadm:  %s environment is disabled; skipping\n", cur_env);
@@ -1256,8 +1460,7 @@ void fm_configure (void)
     char usrrtn[4096];
     char usrgbl[4096];
 
-    char locktab[4096];
-    char zalloctab[4096];
+    char jnldir[4096];
     char jnlfile[4096];
     char jnlmode[4];
     char jnlhostid[4096];    
@@ -1282,8 +1485,13 @@ void fm_configure (void)
 
     char *username = env_user;
     char *groupname = env_group;
-   
+    
 #if !defined(__OS2__)
+    if (geteuid () != 0) {
+        fprintf (stderr, "fmadm:  not superuser\n");
+        exit (1);
+    }
+
     struct group *d_grp;
     struct passwd *d_user;
     gid_t d_gid;
@@ -1301,17 +1509,15 @@ void fm_configure (void)
     }
     d_uid = d_user->pw_uid;
 #endif    
-    
-    
+        
     snprintf (varbase, 4095, "%s/freem", LOCALSTATEDIR);
     snprintf (rundir, 4095, "%s/freem/run", LOCALSTATEDIR);
     snprintf (sysrtn, 4095, "%s/freem/%s/SYSTEM/routines", LOCALSTATEDIR, fma_environment);
     snprintf (sysgbl, 4095, "%s/freem/%s/SYSTEM/globals", LOCALSTATEDIR, fma_environment);
     snprintf (usrrtn, 4095, "%s/freem/%s/USER/routines", LOCALSTATEDIR, fma_environment);
     snprintf (usrgbl, 4095, "%s/freem/%s/USER/globals", LOCALSTATEDIR, fma_environment);
-    snprintf (locktab, 4095, "/tmp/locktab");
-    snprintf (zalloctab, 4095, "/tmp/zalloctab");
-    snprintf (jnlfile, 4095, "/tmp/freem_journal_%s.dat", fma_environment);
+    snprintf (jnldir, 4095, "%s/freem/%s/journals", LOCALSTATEDIR, fma_environment);
+    snprintf (jnlfile, 4095, "%s/freem_journal_%s.dat", jnldir, fma_environment);
     snprintf (jnlmode, 3, "on");
     snprintf (jnlhostid, 4095, "DEFAULT");
     snprintf (jnlcut, 4095, "4294967000");
@@ -1366,41 +1572,48 @@ void fm_configure (void)
     
     /* check for existence of needed directories */
     if (stat (SYSCONFDIR, &etcstat) == -1) {
-	fprintf (stderr, "fmadm:  creating %s\n", SYSCONFDIR);
+	fprintf (stderr, "fmadm:  creating %s [SYSCONFDIR]\n", SYSCONFDIR);
 	mkdir (SYSCONFDIR, 0775);
         set_permissions (SYSCONFDIR, username, groupname, 0775);
     }
 
     if (stat (confbase, &etcstat) == -1) {
-        fprintf (stderr, "fmadm:  creating %s\n", confbase);
+        fprintf (stderr, "fmadm:  creating %s [confbase]\n", confbase);
         mkdir (confbase, 0775);
         set_permissions (confbase, username, groupname, 0775);
     }
 
-    if (stat (envbase, &etcstat) == -1) {
-        fprintf (stderr, "fmadm:  creating %s\n", envbase);
-        mkdir (envbase, 0775);
-        set_permissions (envbase, username, groupname, 0775);
-    }
-
     if (stat (varbase, &etcstat) == -1) {
-        fprintf (stderr, "fmadm:  creating %s\n", varbase);
+        fprintf (stderr, "fmadm:  creating %s [varbase]\n", varbase);
         mkdir (varbase, 0775);
         set_permissions (varbase, username, groupname, 0775);
     }
 
+    if (stat (envbase, &etcstat) == -1) {
+        fprintf (stderr, "fmadm:  creating %s [envbase]\n", envbase);
+        mkdir (envbase, 0775);
+        set_permissions (envbase, username, groupname, 0775);
+    }
+    
     if (stat (rundir, &etcstat) == -1) {
-        fprintf (stderr, "fmadm:  creating %s\n", rundir);
+        fprintf (stderr, "fmadm:  creating %s [rundir]\n", rundir);
         mkdir (rundir, 0777);
         chmod (rundir, 0777);
     }
 
     if (stat (nsbase, &etcstat) == -1) {
-        fprintf (stderr, "fmadm:  creating %s\n", nsbase);
+        fprintf (stderr, "fmadm:  creating %s [nsbase]\n", nsbase);
         mkdir (nsbase, 0775);
         set_permissions (nsbase, username, groupname, 0775);
     }
 
+    if (stat (jnldir, &etcstat) == -1) {
+        fprintf (stderr, "fmadm:  creating %s [jnldir]\n", jnldir);
+        mkdir (jnldir, 0775);   
+        set_permissions (jnldir, username, groupname, 0775);
+    }
+
+    
     snprintf (src_dir, 4095, "%s/freem/mlib", DATADIR);
     snprintf (dest_dir, 4095, "%s/freem/%s/SYSTEM/routines", LOCALSTATEDIR, fma_environment);
     
@@ -1430,7 +1643,7 @@ void fm_configure (void)
     mkdir (buf, 0775);
     set_permissions (buf, username, groupname, 0775);
     
-    fprintf (stderr, "fmadm:  copying routines from '%s' to '%s'...\n", src_dir, dest_dir);
+    fprintf (stderr, "fmadm:  copying vendor routines from '%s' to '%s'...\n", src_dir, dest_dir);
 
     if ((dir = opendir (src_dir)) == NULL) {
         fprintf (stderr, "\nfmadm:  could not open source directory %s\n", src_dir);
@@ -1441,13 +1654,19 @@ void fm_configure (void)
         char infile[4096];
         char outfile[4096];
         
-        if ((strcmp (ent->d_name, ".") != 0) && (strcmp (ent->d_name, "..") != 0)) {
-            
-            fprintf (stderr, "\t%s\n", ent->d_name);
+        if ((strcmp (ent->d_name, ".") != 0) && (strcmp (ent->d_name, "..") != 0)) {           
             
             snprintf (infile, 4095, "%s/%s", src_dir, ent->d_name);
             snprintf (outfile, 4095, "%s/%s", dest_dir, ent->d_name);
 
+            if (stat (outfile, &etcstat) == 0) {
+                unlink (outfile);
+                fprintf (stderr, "\tupgrade -> %s\n", ent->d_name);
+            }
+            else {
+                fprintf (stderr, "\tnew     -> %s\n", ent->d_name);
+            }
+            
 #if !defined(__OS2__)            
             if (cp (outfile, infile) != 0) {
                 fprintf (stderr, "fmadm:  failure copying %s to %s\n", infile, outfile);
@@ -1463,27 +1682,46 @@ void fm_configure (void)
         
     }
 
-    fp = fopen (env_config_file, "a+");
-
-    fprintf (stderr, "Creating %s... ", env_config_file);
-
-    snprintf (buf, 4095, "[%s]", fma_environment);
-    fm_write (fp, buf);
-
-    snprintf (buf, 4095, "user=%s", env_user);
-    fm_write (fp, buf);
-    
-    snprintf (buf, 4095, "group=%s", env_group);
-    fm_write (fp, buf);
+    if (fm_validate_environment (fma_environment) == FALSE) {
+        fp = fopen (env_config_file, "a+");
+        
+        fprintf (stderr, "Creating %s... ", env_config_file);
+        
+        snprintf (buf, 4095, "[%s]", fma_environment);
+        fm_write (fp, buf);
+        
+        snprintf (buf, 4095, "user=%s", env_user);
+        fm_write (fp, buf);
+        
+        snprintf (buf, 4095, "group=%s", env_group);
+        fm_write (fp, buf);
+        
+        snprintf (buf, 4095, "enabled=true");
+        fm_write (fp, buf);
+        
+        snprintf (buf, 4095, "env_path=%s/freem/%s", LOCALSTATEDIR, fma_environment);
+        fm_write (fp, buf);
+        
+        fclose (fp);
+        fprintf (stderr, "[OK]\n");
+    }
+    else {
+        char modtmp[255];
+        
+        fprintf (stderr, "Updating %s: \n", env_config_file);
+        
+        read_profile_string (env_config_file, fma_environment, "user", modtmp);
+        if (strcmp (env_user, modtmp) != 0) {
+            modify_profile_string (env_config_file, fma_environment, "user", env_user);
+            fprintf (stderr, "\tuser:   %s -> %s\n", modtmp, env_user);
+        }
 
-    snprintf (buf, 4095, "enabled=true");
-    fm_write (fp, buf);
-    
-    snprintf (buf, 4095, "env_path=%s/freem/%s", LOCALSTATEDIR, fma_environment);
-    fm_write (fp, buf);
-    
-    fclose (fp);
-    fprintf (stderr, "[OK]\n");
+        read_profile_string (env_config_file, fma_environment, "group", modtmp);
+        if (strcmp (env_group, modtmp) != 0) {
+            modify_profile_string (env_config_file, fma_environment, "group", env_group);
+            fprintf (stderr, "\tgroup:  %s -> %s\n", modtmp, env_group);
+        }
+    }
    
     fp = fopen (config_file, "a+");