--- freem/src/fmadm.c	2025/04/01 14:32:11	1.19
+++ freem/src/fmadm.c	2025/04/02 04:50:49	1.25
@@ -1,5 +1,5 @@
 /*
- *   $Id: fmadm.c,v 1.19 2025/04/01 14:32:11 snw Exp $
+ *   $Id: fmadm.c,v 1.25 2025/04/02 04:50:49 snw Exp $
  *    FreeM Administration Tool
  *
  *  
@@ -24,6 +24,24 @@
  *   along with FreeM.  If not, see <https://www.gnu.org/licenses/>.
  *
  *   $Log: fmadm.c,v $
+ *   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
  *
@@ -144,13 +162,19 @@ 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];
 
 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);
+extern int read_profile_string(char *file, char *section, char *key, char *value);
 
 int main (int argc, char **argv)
 {
@@ -198,6 +222,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] != '=') {
@@ -211,6 +270,11 @@ 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++;
@@ -238,18 +302,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 ();
@@ -259,6 +336,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 act_switch;
+        }
+        else if (strcmp (argv[1], "stop") == 0 && strcmp (argv[2], "environment") == 0) {
+            act = ACT_STOP;
+            obj = OBJ_DAEMON;
+            goto act_switch;
+        }
+        else if (strcmp (argv[1], "restart") == 0  && strcmp (argv[2], "environment") == 0) {
+            act = ACT_RESTART;
+            obj = OBJ_DAEMON;
+            goto act_switch;
+        }
+        else if (strcmp (argv[1], "status") == 0  && strcmp (argv[2], "environment") == 0) {
+            act = ACT_STATUS;
+            obj = OBJ_DAEMON;
+            goto act_switch;
+        }        
+
     }
 
     pid = getpid ();
@@ -269,7 +367,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 ();    
     
@@ -277,71 +375,6 @@ 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);
     
@@ -383,18 +416,23 @@ 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 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;
@@ -430,6 +468,7 @@ int main (int argc, char **argv)
     stcnv_c2m (glopath);
 
 
+act_switch:
     switch (act) {
 
         
@@ -484,6 +523,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();
@@ -636,7 +680,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;
@@ -836,10 +879,12 @@ int fmadm_usage (void)
     
     fprintf (stdout, "        <action> can be one of:\n");
     fprintf (stdout, "            list, examine, verify, compact, repair, create, remove,\n");
-    fprintf (stdout, "            import, export, backup, restore, migrate, edit\n\n");
+    fprintf (stdout, "            import, export, backup, restore, migrate, edit, start,\n");
+    fprintf (stdout, "            stop, restart\n\n");
 
     fprintf (stdout, "        <object> can be one of:\n");
-    fprintf (stdout, "            lock, zallocate, journal, namespace, global, routine, job\n\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");
     fprintf (stdout, "    for details on fmadm usage and options.\n\n");
@@ -1074,6 +1119,177 @@ 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_daemonctl (short action, short object, int optc, char **options)
+{
+    FILE *ef;
+    char *envlist;
+    char env[255];
+    char line[255];
+    char tmps[255];
+    char *cur_env;
+    char cmd[4096];
+    char verb[40];
+    char e_user[255];
+    char e_grp[255];
+    char e_ena[10];
+    char basecmd[255];    
+    char *savptr;
+    int result;
+    long epid;
+
+#if !defined(__OS2__)
+    snprintf (basecmd, 254, "%s/bin/freem", PREFIX);
+#else
+    snprintf (basecmd, 254, "%s/bin/freemd.exe", PREFIX);
+#endif
+    
+    switch (action) {
+        case ACT_START:
+            sprintf (verb, "starting");
+            break;
+        case ACT_STOP:
+            sprintf (verb, "stopping");
+            break;
+        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 = (char *) malloc (sizeof (char) * BIGSTR);
+        NULLPTRCHK(envlist,"fm_daemonctl");
+
+        strcpy (envlist, options[0]);
+    }
+    else {
+        /* no environment specified; do 'action' for all environments */
+        envlist = (char *) malloc (sizeof (char) * BIGSTR);
+        NULLPTRCHK(envlist,"fm_daemonctl");
+
+        ef = fopen (env_config_file, "r");
+
+        while (fgets (line, 254, ef)) {
+            if (line[0] == '[') {
+                strncpy (env, &(line[1]), 255);
+                env[strlen (env) - 2] = '\0';
+                snprintf (tmps, 255, "%s,", env);
+                strncat (envlist, tmps, BIGSTR - 1);
+            }
+        }
+        envlist[strlen (envlist) - 1] = '\0';
+
+        fclose (ef);        
+    }
+
+    savptr = envlist;
+    cur_env = strtok_r (envlist, ",", &savptr);
+    do {
+        result = read_profile_string (env_config_file, cur_env, "enabled", e_ena);        
+        if (result == FALSE || strcmp (e_ena, "true") == 0) {
+
+            result = read_profile_string (env_config_file, cur_env, "user", e_user);
+            if (result == FALSE) {
+                strcpy (e_user, "freem");
+            }
+            result = read_profile_string (env_config_file, cur_env, "group", e_grp);
+            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
+                    system (cmd);
+                    break;
+                case ACT_STOP:
+                    epid = fm_get_pid (cur_env);
+                    if (epid > -1) {
+                        fprintf (stderr, "fmadm:  stopping environment daemon pid %d\n", epid);
+                        kill (epid, SIGINT);
+                        kill (epid, SIGTERM);
+                    }
+                    else {
+                        fprintf (stderr, "fmadm:  could not obtain environment daemon pid\n");
+                    }
+                    
+                    break;
+                case ACT_RESTART:
+                    epid = fm_get_pid (cur_env);
+                    if (epid > -1) {
+                        fprintf (stderr, "fmadm:  stopping environment daemon pid %d\n", epid);
+                        kill (epid, SIGINT);
+                        kill (epid, SIGTERM);
+                    }
+                    else {
+                        fprintf (stderr, "fmadm:  could not obtain environment daemon pid\n");
+                    }
+                    fprintf (stderr, "fmadm:  waiting 2 seconds\n");
+                    sleep (2);
+                    fprintf (stderr, "fmadm:  starting environment %s\n", cur_env);
+#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
+                    system (cmd);
+                    
+
+                    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);
+        }
+    } while ((cur_env = strtok_r (NULL, ",", &savptr)) != NULL);
+
+    free (envlist);
+    exit (0);
+    
+} /* fm_daemonctl() */
+
 void fm_checkperms(void)
 {
 
@@ -1117,14 +1333,14 @@ void fm_reconfigure(void)
 
 void fm_configure (void)
 {
+    char rundir[4096];
     char varbase[4096];
     char sysrtn[4096];
     char sysgbl[4096];
     char usrrtn[4096];
     char usrgbl[4096];
 
-    char locktab[4096];
-    char zalloctab[4096];
+    char jnldir[4096];
     char jnlfile[4096];
     char jnlmode[4];
     char jnlhostid[4096];    
@@ -1147,20 +1363,41 @@ void fm_configure (void)
     char src_dir[4096];
     char dest_dir[4096];
 
+    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;
-    uid_t d_uid;   
+    uid_t d_uid;
 
-    
+    if ((d_grp = getgrnam (groupname)) == NULL) {
+        fprintf (stderr, "fmadm:  '%s' group must exist before configuring\n", groupname);
+        exit (1);
+    }
+    d_gid = d_grp->gr_gid;
+
+    if ((d_user = getpwnam (username)) == NULL) {
+        fprintf (stderr, "fmadm:  '%s' user must exist before configuring\n", username);
+        exit (1);
+    }
+    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");
@@ -1169,20 +1406,6 @@ void fm_configure (void)
         fprintf (stderr, "fmadm:  not superuser\n");
         exit (1);
     }
-
-#if !defined(__OS2__)
-    if ((d_grp = getgrnam ("freem")) == NULL) {
-        fprintf (stderr, "fmadm:  'freem' group must exist before configuring\n");
-        exit (1);
-    }
-    d_gid = d_grp->gr_gid;
-
-    if ((d_user = getpwnam ("freem")) == NULL) {
-        fprintf (stderr, "fmadm:  'freem' user must exist before configuring\n");
-        exit (1);
-    }
-    d_uid = d_user->pw_uid;
-#endif
     
     if (file_exists (config_file)) {
         fprintf (stderr, "fmadm:  '%s' already exists; running fmadm reconfigure instead\n", config_file);
@@ -1190,12 +1413,10 @@ void fm_configure (void)
         return;
     }
 
-
     gethostname (hostid, 4095);
     uuid_v4 (buf);
 
     snprintf (jnlhostid, 4095, "%s:%s", hostid, buf);
-
     snprintf (confbase, 4095, "%s/freem", SYSCONFDIR);
     snprintf (envbase, 4095, "%s/freem/%s", SYSCONFDIR, fma_environment); 
     snprintf (nsbase, 4095, "%s/freem/%s", LOCALSTATEDIR, fma_environment);
@@ -1227,67 +1448,52 @@ void fm_configure (void)
     printf ("---------------------------\n\n");
 
     printf ("This utility will create the initial configuration file for ");
-    printf ("FreeM environment '%s' in %s.\n\n", fma_environment, config_file);    
+    printf ("FreeM environment '%s' (owned by %s:%s) in '%s'.\n\n", fma_environment, username, groupname, config_file);    
     
     /* 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);
-#if !defined(__OS2__)
-        if (chown (SYSCONFDIR, d_uid, d_gid) != 0) {
-            fprintf (stderr, "fmadm:  error setting ownership on %s\n", SYSCONFDIR);
-            exit (1);
-        }
-#endif        
+        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);
-#if !defined(__OS2__)
-        if (chown (confbase, d_uid, d_gid) != 0) {
-            fprintf (stderr, "fmadm:  error setting ownership on %s\n", confbase);
-            exit (1);
-        }
-#endif        
-    }
-
-    if (stat (envbase, &etcstat) == -1) {
-        fprintf (stderr, "fmadm:  creating %s\n", envbase);
-        mkdir (envbase, 0775);
-#if !defined(__OS2__)
-        if (chown (envbase, d_uid, d_gid) != 0) {
-            fprintf (stderr, "fmadm:  error setting ownership on %s\n", envbase);
-            exit (1);
-        }
-#endif        
-        
+        set_permissions (confbase, 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);
-#if !defined(__OS2__)
-        if (chown (varbase, d_uid, d_gid) != 0) {
-            fprintf (stderr, "fmadm:  error setting ownership on %s\n", varbase);
-            exit (1);
-        }
-#endif        
-        
+        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 [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);
-#if !defined(__OS2__)
-        if (chown (nsbase, d_uid, d_gid) != 0) {
-            fprintf (stderr, "fmadm:  error setting ownership on %s\n", nsbase);
-            exit (1);
-        }
-#endif        
-        
+        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);
     
@@ -1295,60 +1501,29 @@ void fm_configure (void)
     
     snprintf (buf, 4095, "%s/freem/%s/SYSTEM", LOCALSTATEDIR, fma_environment);
     mkdir (buf, 0775);
-#if !defined(__OS2__)
-    if (chown (buf, d_uid, d_gid) != 0) {
-        fprintf (stderr, "fmadm:  error setting ownership on %s\n", buf);
-        exit (1);
-    }
-#endif        
-    
+    set_permissions (buf, username, groupname, 0775);
     
     snprintf (buf, 4095, "%s/freem/%s/USER", LOCALSTATEDIR, fma_environment);
     mkdir (buf, 0775);
-#if !defined(__OS2__)
-    if (chown (buf, d_uid, d_gid) != 0) {
-        fprintf (stderr, "fmadm:  error setting ownership on %s\n", buf);
-        exit (1);
-    }
-#endif        
+    set_permissions (buf, username, groupname, 0775);
     
     snprintf (buf, 4095, "%s/freem/%s/SYSTEM/routines", LOCALSTATEDIR, fma_environment);
     mkdir (buf, 0775);
-#if !defined(__OS2__)
-    if (chown (buf, d_uid, d_gid) != 0) {
-        fprintf (stderr, "fmadm:  error setting ownership on %s\n", buf);
-        exit (1);
-    }
-#endif        
+    set_permissions (buf, username, groupname, 0775);
     
     snprintf (buf, 4095, "%s/freem/%s/USER/globals", LOCALSTATEDIR, fma_environment);
     mkdir (buf, 0775);
-#if !defined(__OS2__)
-    if (chown (buf, d_uid, d_gid) != 0) {
-        fprintf (stderr, "fmadm:  error setting ownership on %s\n", buf);
-        exit (1);
-    }
-#endif        
+    set_permissions (buf, username, groupname, 0775);
     
     snprintf (buf, 4095, "%s/freem/%s/SYSTEM/globals", LOCALSTATEDIR, fma_environment);
     mkdir (buf, 0775);
-#if !defined(__OS2__)
-    if (chown (buf, d_uid, d_gid) != 0) {
-        fprintf (stderr, "fmadm:  error setting ownership on %s\n", buf);
-        exit (1);
-    }
-#endif        
+    set_permissions (buf, username, groupname, 0775);
     
     snprintf (buf, 4095, "%s/freem/%s/USER/routines", LOCALSTATEDIR, fma_environment);
     mkdir (buf, 0775);
-#if !defined(__OS2__)
-    if (chown (buf, d_uid, d_gid) != 0) {
-        fprintf (stderr, "fmadm:  error setting ownership on %s\n", buf);
-        exit (1);
-    }
-#endif        
+    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);
@@ -1359,21 +1534,24 @@ 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);
             }
-            if (chown (outfile, d_uid, d_gid) != 0) {
-                fprintf (stderr, "fmadm:  error setting ownership on %s\n", outfile);
-                exit (1);
-            }
+            set_permissions (outfile, username, groupname, 0755);
 #else
             if (DosCopy (infile, outfile, 1) != 0) {
                 fprintf (stderr, "fmadm:  failure copying %s to %s\n", infile, outfile);
@@ -1383,10 +1561,32 @@ 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);
+
+    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");
    
     fp = fopen (config_file, "a+");
     
-    printf ("Creating %s... ", config_file); 
+    fprintf (stderr, "Creating %s... ", config_file); 
     
     snprintf (buf, 4095, "[SYSTEM]");
     fm_write (fp, buf);
@@ -1429,40 +1629,11 @@ void fm_configure (void)
 
     snprintf (buf, 4095, "globals_path=%s", usrgbl);
     fm_write (fp, buf);
-    
-    
+        
     fclose (fp);
+    set_permissions (config_file, username, groupname, 0755);
+    fprintf (stderr, "[OK]\n");
 
-#if !defined(__OS2__)
-    if (chown (config_file, d_uid, d_gid) != 0) {
-        printf ("[FAIL]\n\n");
-        fprintf (stderr, "fmadm:  error setting ownership on %s\n", config_file);
-        exit (1);
-    }
-#endif    
-    
-    printf ("[OK]\n\n");
-
-/*
-    printf ("Setting USER namespace permissions... ");
-
-    snprintf (buf, 4095, "%s/freem/USER/globals", LOCALSTATEDIR);
-    chmod (buf, 0777);
-
-    snprintf (buf, 4095, "%s/freem/USER/routines", LOCALSTATEDIR);
-    chmod (buf, 0777);
-
-    printf ("[OK]\n");
-    printf ("Setting SYSTEM namespace permissions... ");
-    
-    snprintf (buf, 4095, "%s/freem/SYSTEM/globals", LOCALSTATEDIR);
-    chmod (buf, 0755);
-
-    snprintf (buf, 4095, "%s/freem/SYSTEM/routines", LOCALSTATEDIR);
-    chmod (buf, 0755);
-
-    printf ("[OK]\n\n\n");
-*/
     printf ("FreeM initial configuration is complete.\n\n");
 
     printf (" USER globals:                   %s\n", usrgbl);
@@ -1476,6 +1647,43 @@ void fm_configure (void)
     
 } /* fm_configure */
 
+void set_permissions(char *path, char *user, char *grp, int mode)
+{
+    
+#if !defined(__OS2__)
+    struct group *d_grp;
+    struct passwd *d_user;
+    gid_t d_gid;
+    uid_t d_uid;
+#endif    
+
+
+#if !defined(__OS2__)    
+    if ((d_grp = getgrnam (grp)) == NULL) {
+        fprintf (stderr, "fmadm:  '%s' group must exist before configuring\n", grp);
+        exit (1);
+    }
+    d_gid = d_grp->gr_gid;
+
+    if ((d_user = getpwnam (user)) == NULL) {
+        fprintf (stderr, "fmadm:  '%s' user must exist before configuring\n", user);
+        exit (1);
+    }
+    d_uid = d_user->pw_uid;
+
+    if (chown (path, d_uid, d_gid) != 0) {
+        fprintf (stderr, "fmadm:  error setting ownership on %s\n", path);
+        exit (1);
+    }
+#endif    
+
+    if (chmod (path, mode) != 0) {
+        fprintf (stderr, "fmadm:  error setting permissions on %s to %d\n", path, mode);
+        exit (1);
+    }
+    
+}
+
 void fm_write (FILE *file, char *buf)
 {
     fprintf (file, "%s\n", buf);