File:  [Coherent Logic Development] / freem / src / fmadm.c
Revision 1.17: download - view: text, annotated - select for diffs
Sun Mar 30 01:36:58 2025 UTC (2 days, 22 hours ago) by snw
Branches: MAIN
CVS tags: HEAD
Make it easier to bring back fma_gedit, fix double-free in global handler, limit $CHAR to 7-bit ASCII

/*
 *   $Id: fmadm.c,v 1.17 2025/03/30 01:36:58 snw Exp $
 *    FreeM Administration Tool
 *
 *  
 *   Author: Serena Willis <snw@coherent-logic.com>
 *    Copyright (C) 1998 MUG Deutschland
 *    Copyright (C) 2020, 2023, 2025 Coherent Logic Development LLC
 *
 *
 *   This file is part of FreeM.
 *
 *   FreeM is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   FreeM is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Affero Public License for more details.
 *
 *   You should have received a copy of the GNU Affero Public License
 *   along with FreeM.  If not, see <https://www.gnu.org/licenses/>.
 *
 *   $Log: fmadm.c,v $
 *   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
 *
 *   Revision 1.8  2025/03/22 18:43:54  snw
 *   Make STRLEN 255 chars and add BIGSTR macro for larger buffers
 *
 *   Revision 1.7  2025/03/09 19:14:25  snw
 *   First phase of REUSE compliance and header reformat
 *
 *
 * SPDX-FileCopyrightText:  (C) 2025 Coherent Logic Development LLC
 * SPDX-License-Identifier: AGPL-3.0-or-later 
 **/

#include <sys/types.h>
#include <sys/stat.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include "config.h"
#include "transact.h"
#include "namespace.h"
#include "fs.h"

#if defined(__OS2__)
# include <os2.h>
#endif

#ifdef HAVE_LIBREADLINE
#  if defined(HAVE_READLINE_READLINE_H)
#    include <readline/readline.h>
#  elif defined(HAVE_READLINE_H)
#    include <readline.h>
#  else /* !defined(HAVE_READLINE_H) */
extern char *readline ();
#  endif /* !defined(HAVE_READLINE_H) */
/*char *cmdline = NULL;*/
#else /* !defined(HAVE_READLINE_READLINE_H) */
  /* no readline */
#endif /* HAVE_LIBREADLINE */

#ifdef HAVE_READLINE_HISTORY
#  if defined(HAVE_READLINE_HISTORY_H)
#    include <readline/history.h>
#  elif defined(HAVE_HISTORY_H)
#    include <history.h>
#  else /* !defined(HAVE_HISTORY_H) */
extern void add_history ();
extern int write_history ();
extern int read_history ();
#  endif /* defined(HAVE_READLINE_HISTORY_H) */
  /* no history */
#endif /* HAVE_READLINE_HISTORY */


#include "fmadm.h"
#include "errmsg.h"
#include "iniconf.h"
#include "init.h"
#include "version.h"
#include "shmmgr.h"
#include "jobtab.h"
#include "locktab.h"

/* namespace configuration */
char fma_environment[STRLEN];
char fma_namespace[STRLEN];
char fma_routine_path[PATHLEN];
char fma_global_path[PATHLEN];
char fma_journal_path[PATHLEN];
char fma_pct_global_path[PATHLEN];
char fma_pct_routine_path[PATHLEN];
char fma_journal_cut_threshold[STRLEN];
char fma_locktab[PATHLEN];
short fma_base_opt = 1;
short fma_min_args = 2;
short fma_explicit_namespace = FALSE;
short fma_explicit_environment = FALSE;

/* miscellaneous global state */
char obj_str[STRLEN];

extern char config_file[4096];

int fm_shell(void);
void fm_checkperms(void);
void fm_reconfigure(void);
void fm_configure(void);
void fm_write (FILE *file, char *buf);
int fma_jobs_remove (int optc, char **opts);

int main (int argc, char **argv)
{
    char action[STRLEN];    

    short act = -1;
    short obj = -1;

    char **opts;
    int optc = argc - 3;

    int i = 0;
    int j = 1;
    int base_arg = 4;
    int k = 0;

    short got_action = FALSE;
    short got_object = FALSE;


    /* snprintf (config_file, 4096, "%s/freem.conf", SYSCONFDIR); */

    base_arg = 1;

    /* enforce action in argv[1] */
    if (argc > 1) {
        if (argv[1][0] == '-') {
            fprintf (stderr, "fmadm:  first argument, if given, must be an action, not a flag\n");
            fmadm_usage ();
            exit (1);
        }
    }
    
    for (i = base_arg; i < argc; i++) {
        if (i == 1 && isalpha (argv[i][0])) {
            got_action = TRUE;
            strncpy (action, argv[i], STRLEN - 1);
            base_arg++;
        }
        if (i == 2 && isalpha (argv[i][0])) {
            got_object = TRUE;
            strncpy (obj_str, argv[i], STRLEN - 1);
            base_arg++;
        }
        if (argv[i][0] == '-') {
                        
            switch (argv[i][1]) {
                
                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++) {
                        fma_environment[k++] = argv[i][j];
                    }
                    
                    fma_explicit_environment = TRUE;
                    base_arg++;
                    
                    break;
                    
                case 'n':
                    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++) {
                        fma_namespace[k++] = argv[i][j];
                    }
                    
                    fma_explicit_namespace = TRUE;
                    base_arg++;
                    
                    break;                                                

            }
        }
    }

    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);

    /*
    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 */
    if (got_action) {
        if (strcmp (argv[1], "configure") == 0) {
            fm_configure ();
            exit (0);
        }
        else if (strcmp (argv[1], "reconfigure") == 0) {
            fm_reconfigure ();
            exit (0);
        }
    }

    pid = getpid ();
    
    shm_init (16777216);
    tp_init ();
    jobtab_init ();
    job_init (TRUE);

    fm_sig_init ();
    
    /* go to fmadm shell if no arguments passed */
    if (!got_action && !got_object) return fm_shell ();    
    
    if (argc > 1 && strcmp (argv[1], "checkperms") == 0) {
	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);
    
    /* allocate opts array */
    
    /* first dimension */
    if ((opts = (char **) malloc (FMA_MAXARGS * sizeof (char *))) == NULL) {	
        fprintf (stderr, "fmadm [FATAL]:  could not acquire memory\n");
        return 1;
    } 

    /* second dimension */
    for (i = 0; i < FMA_MAXARGS; i++) {
        if ((opts[i] = (char *) malloc (STRLEN * sizeof (char *))) == NULL) {
            fprintf (stderr, "fmadm [FATAL]:  could not acquire memory\n");
            return 1;
        } 
    }

    /* copy argv[base_arg] through argv[argc - 1] to opts[1] through opts[argc - 3] */
    
    strncpy (opts[0], argv[0], STRLEN - 1); /* preserve argv[0] */

    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 */
        strncpy (opts[j++], argv[i], STRLEN - 1);
    }
    
    if (strncmp (action, "list", STRLEN - 1) == 0) act = ACT_LIST;
    else if (strncmp (action, "examine", STRLEN - 1) == 0) act = ACT_EXAMINE;
    else if (strncmp (action, "verify", STRLEN - 1) == 0) act = ACT_VERIFY;
    else if (strncmp (action, "compact", STRLEN - 1) == 0) act = ACT_COMPACT;
    else if (strncmp (action, "repair", STRLEN - 1) == 0) act = ACT_REPAIR;
    else if (strncmp (action, "create", STRLEN - 1) == 0) act = ACT_CREATE;
    else if (strncmp (action, "remove", STRLEN - 1) == 0) act = ACT_REMOVE;
    else if (strncmp (action, "import", STRLEN - 1) == 0) act = ACT_IMPORT;
    else if (strncmp (action, "export", STRLEN - 1) == 0) act = ACT_EXPORT;
    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 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 return fmadm_usage();

    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;
    }   

    if (get_conf (fma_namespace, "globals_path", fma_global_path) == FALSE) {
        fprintf (stderr, "fmadm:  cannot determine global path for namespace %s\n", fma_namespace);
        return 1;
    }   

    if (get_conf ("SYSTEM", "globals_path", fma_pct_global_path) == FALSE) {
        fprintf (stderr, "fmadm:  cannot determine %% global path for namespace %s\n", "SYSTEM");
        return 1;
    }

    if (get_conf ("SYSTEM", "routines_path", fma_pct_routine_path) == FALSE) {
        fprintf (stderr, "fmadm:  cannot determine %% routine path for namespace %s\n", "SYSTEM");
        return 1;
    }

    if (get_conf ("SYSTEM", "journal_file", fma_journal_path) == FALSE) {
        strcpy (fma_journal_path, "");
    }

    if (get_conf ("SYSTEM", "journal_cut_threshold", fma_journal_cut_threshold) == FALSE) {
        strcpy (fma_journal_cut_threshold, "1073741824");
    }
    
    strcpy (gloplib, fma_pct_global_path);
    stcnv_c2m (gloplib);

    strcpy (glopath, fma_global_path);
    stcnv_c2m (glopath);


    switch (act) {

        
        case ACT_LIST:
            fmadm_exit (fm_list (obj, optc, opts));


        case ACT_EXAMINE:
            fmadm_exit (fm_examine (obj, optc, opts));


        case ACT_VERIFY:
            fmadm_exit (fm_verify (obj, optc, opts));


        case ACT_COMPACT:
            fmadm_exit (fm_compact (obj, optc, opts));


        case ACT_REPAIR:
            fmadm_exit (fm_repair (obj, optc, opts));


        case ACT_CREATE:
            fmadm_exit (fm_create (obj, optc, opts));


        case ACT_REMOVE:
            fmadm_exit (fm_remove (obj, optc, opts));


        case ACT_IMPORT:
            fmadm_exit (fm_import (obj, optc, opts));


        case ACT_EXPORT:
            fmadm_exit (fm_export (obj, optc, opts));


        case ACT_BACKUP:
            fmadm_exit (fm_backup (obj, optc, opts));


        case ACT_RESTORE:
            fmadm_exit (fm_restore (obj, optc, opts));


        case ACT_MIGRATE:
            fmadm_exit (fm_migrate (obj, optc, opts));


        case ACT_EDIT:
            fmadm_exit (fm_edit (obj, optc, opts));


        default:
            return fmadm_usage();
    }

    return 0;   /* should never be reached */

} /* main() */

int fm_shell (void)
{
    
#if defined(HAVE_LIBREADLINE) && !defined(_AIX)
    int cmd;
    int i;
    int j;
    int obj;
    int optc;
    int argc;
    char **args;
    char **opts;    
    char *fmarl_buf;
    char *fma_prompt = (char *) malloc (STRLEN * sizeof (char));
    char *cmdt = (char *) malloc (65535 * sizeof (char));
    char *result = (char *) malloc (65535 * sizeof (char));

    /*
    strcpy (fma_namespace, "SYSTEM");
    set_namespace (fma_namespace, FALSE);
    */
    
    snprintf (fma_prompt, STRLEN - 1, "fmadm [%s]> ", fma_namespace);
    
    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;
    }   

    if (get_conf (fma_namespace, "globals_path", fma_global_path) == FALSE) {
        fprintf (stderr, "fmadm:  cannot determine global path for namespace %s\n", fma_namespace);
        return 1;
    }   

    if (get_conf ("SYSTEM", "globals_path", fma_pct_global_path) == FALSE) {
        fprintf (stderr, "fmadm:  cannot determine %% global path for namespace %s\n", "SYSTEM");
        return 1;
    }

    if (get_conf ("SYSTEM", "routines_path", fma_pct_routine_path) == FALSE) {
        fprintf (stderr, "fmadm:  cannot determine %% routine path for namespace %s\n", "SYSTEM");
        return 1;
    }

    if (get_conf ("SYSTEM", "journal_file", fma_journal_path) == FALSE) {
        strcpy (fma_journal_path, "");
    }

    if (get_conf ("SYSTEM", "journal_cut_threshold", fma_journal_cut_threshold) == FALSE) {
        strcpy (fma_journal_cut_threshold, "1073741824");
    }
    
    strcpy (gloplib, fma_pct_global_path);
    stcnv_c2m (gloplib);

    strcpy (glopath, fma_global_path);
    stcnv_c2m (glopath);
    
    /* allocate args array */
    
    /* first dimension */
    if ((args = (char **) malloc (FMA_MAXARGS * sizeof (char *))) == NULL) {	
        fprintf (stderr, "fmadm [FATAL]:  could not acquire memory\n");
        return 1;
    } 

    /* second dimension */
    for (i = 0; i < FMA_MAXARGS; i++) {
        if ((args[i] = (char *) malloc (STRLEN * sizeof (char *))) == NULL) {
            fprintf (stderr, "fmadm [FATAL]:  could not acquire memory\n");
            return 1;
        } 
    }

    /* allocate opts array */
    
    /* first dimension */
    if ((opts = (char **) malloc (FMA_MAXARGS * sizeof (char *))) == NULL) {	
        fprintf (stderr, "fmadm [FATAL]:  could not acquire memory\n");
        return 1;
    } 

    /* second dimension */
    for (i = 0; i < FMA_MAXARGS; i++) {
        if ((opts[i] = (char *) malloc (STRLEN * sizeof (char *))) == NULL) {
            fprintf (stderr, "fmadm [FATAL]:  could not acquire memory\n");
            return 1;
        } 
    }

    
    for (;;) {

        fmarl_buf = readline (fma_prompt);

        if (fmarl_buf == (char *) NULL) continue;
        
        cmdt = strtok (fmarl_buf, " ");

        if (cmdt == (char *) NULL) continue;
        
        for (i = 0; i < strlen (cmdt); i++) cmdt[i] = cmdt[i] | 0140;        
        
        if (strcmp (cmdt, "exit") == 0) cmd = FMAC_EXIT;
        else if (strcmp (cmdt, "quit") == 0) cmd = FMAC_EXIT;
        else if (strcmp (cmdt, "select") == 0) cmd = FMAC_SELECT;
        else if (strcmp (cmdt, "list") == 0) cmd = FMAC_LIST;
        else if (strcmp (cmdt, "examine") == 0) cmd = FMAC_EXAMINE;
        else if (strcmp (cmdt, "verify") == 0) cmd = FMAC_VERIFY;
        else if (strcmp (cmdt, "compact") == 0) cmd = FMAC_COMPACT;
        else if (strcmp (cmdt, "repair") == 0) cmd = FMAC_REPAIR;
        else if (strcmp (cmdt, "create") == 0) cmd = FMAC_CREATE;
        else if (strcmp (cmdt, "import") == 0) cmd = FMAC_IMPORT;
        else if (strcmp (cmdt, "export") == 0) cmd = FMAC_EXPORT;
        else if (strcmp (cmdt, "backup") == 0) cmd = FMAC_BACKUP;
        else if (strcmp (cmdt, "restore") == 0) cmd = FMAC_RESTORE;
        else if (strcmp (cmdt, "migrate") == 0) cmd = FMAC_MIGRATE;
        else if (strcmp (cmdt, "edit") == 0) cmd = FMAC_EDIT;
        else if (strcmp (cmdt, "set") == 0) cmd = FMAC_SET;
        else if (strcmp (cmdt, "show") == 0) cmd = FMAC_SHOW;
        else if (strcmp (cmdt, "remove") == 0) cmd = FMAC_REMOVE;
        else cmd = FMAC_INVALID;            

        i = 0;
        while ((result = strtok (NULL, " ")) != NULL) {
            //    printf ("%d = %s\n", i, result);
            strcpy (args[i++], result);
        }

        argc = i;
        j = 0;
        
        for (i = 1; i < argc; i++) {
            strncpy (opts[j++], args[i], STRLEN - 1);
        }

        optc = argc - 1;
        
        if (i > 0) {
            
            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;
            else if (strncmp (obj_str, "routine", STRLEN - 1) == 0) obj = OBJ_ROUTINE;
            else if (strncmp (obj_str, "job", STRLEN - 1) == 0) obj = OBJ_JOB;

        }
        
        switch (cmd) {

            
            case FMAC_SELECT:
                
                
                break;

                
            case FMAC_LIST:
                fm_list (obj, optc, opts);
                break;

                
            case FMAC_EXAMINE:
                fm_examine (obj, optc, opts);
                break;


            case FMAC_VERIFY:
                fm_verify (obj, optc, opts);
                break;


            case FMAC_COMPACT:
                fm_compact (obj, optc, opts);
                break;


            case FMAC_REPAIR:
                fm_repair (obj, optc, opts);
                break;


            case FMAC_CREATE:
                fm_create (obj, optc, opts);
                break;


            case FMAC_REMOVE:
                fm_remove (obj, optc, opts);
                break;


            case FMAC_IMPORT:
                fm_import (obj, optc, opts);
                break;


            case FMAC_EXPORT:
                fm_export (obj, optc, opts);
                break;


            case FMAC_BACKUP:
                fm_backup (obj, optc, opts);
                break;


            case FMAC_RESTORE:
                fm_restore (obj, optc, opts);
                break;


            case FMAC_MIGRATE:
                fm_migrate (obj, optc, opts);
                break;


            case FMAC_EDIT:
                fm_edit (obj, optc, opts);
                break;


            case FMAC_SET:

                if (i < 2) {
                    printf ("fmadm:  syntax error\n");
                    break;
                }
                
                if (strcmp (args[0], "namespace") == 0) {
                    strcpy (fma_namespace, args[1]);

                    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;
                    }   
                    
                    if (get_conf (fma_namespace, "globals_path", fma_global_path) == FALSE) {
                        fprintf (stderr, "fmadm:  cannot determine global path for namespace %s\n", fma_namespace);
                        return 1;
                    }   
                    
                    if (get_conf ("SYSTEM", "globals_path", fma_pct_global_path) == FALSE) {
                        fprintf (stderr, "fmadm:  cannot determine %% global path for namespace %s\n", "SYSTEM");
                        return 1;
                    }
                    
                    if (get_conf ("SYSTEM", "routines_path", fma_pct_routine_path) == FALSE) {
                        fprintf (stderr, "fmadm:  cannot determine %% routine path for namespace %s\n", "SYSTEM");
                        return 1;
                    }
                    
                    if (get_conf ("SYSTEM", "journal_file", fma_journal_path) == FALSE) {
                        strcpy (fma_journal_path, "");
                    }
                    
                    if (get_conf ("SYSTEM", "journal_cut_threshold", fma_journal_cut_threshold) == FALSE) {
                        strcpy (fma_journal_cut_threshold, "1073741824");
                    }
                    
                    strcpy (gloplib, fma_pct_global_path);
                    stcnv_c2m (gloplib);
                    
                    strcpy (glopath, fma_global_path);
                    stcnv_c2m (glopath);

                    snprintf (fma_prompt, STRLEN - 1, "fmadm [%s]> ", fma_namespace);
                    
                }
                else if (strcmp (args[0], "maintenance") == 0) {
                    if (strcmp (args[1], "on") == 0) {
                        shm_config->hdr->maintenance_mode = 1;
                        break;
                    }
                    else if (strcmp (args[1], "off") == 0) {
                        shm_config->hdr->maintenance_mode = 0;
                        break;
                    }
                    else {
                        printf ("fmadm:  syntax error\n");
                    }

                    printf ("fmadm:  syntax error\n");
                        
                }
                else {
                    printf ("fmadm:  syntax error\n");
                    break;
                }
                
                break;

                
            case FMAC_SHOW:
                printf ("Namespace:                  %s\n", fma_namespace);
                printf ("Routine Path:               %s\n", fma_routine_path);
                printf ("%%-Routine Path:             %s\n", fma_pct_routine_path);
                printf ("Global Path:                %s\n", fma_global_path);
                printf ("%%-Global Path:              %s\n", fma_pct_global_path);
                printf ("Journal File:               %s\n", fma_journal_path);
                printf ("Journal Cut Threshold:      %s bytes\n", fma_journal_cut_threshold);
                break;

            case FMAC_EXIT:
                fmadm_exit (0);
                break;


            default:
                printf ("fmadm:  '%s' is not a valid fmadm command\n", cmdt);
                break;

        }
    }

#endif
    
}

void fmadm_exit (int retval)
{
    locktab_unlock_all ();
    job_remove (pid);
    
    shm_exit ();

    exit (retval);
}

int fmadm_usage (void)
{

    fprintf (stdout, "\nusage:  fmadm <action> <object> [-e=<environment] [-n=<namespace>] [OPTIONS]\n");
    fprintf (stdout, "        fmadm configure\n");
    fprintf (stdout, "        fmadm reconfigure\n");
    /* fprintf (stdout, "        fmadm checkperms\n\n"); */
    
    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, "        <object> can be one of:\n");
    fprintf (stdout, "            lock, zallocate, journal, namespace, global, routine, job\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");
    
    return 1;

} /* fmadm_usage() */

int fm_list (short object, int optc, char **options)
{

    switch (object) {

        case OBJ_LOCK:
            return fma_locks_list (optc, options);

        case OBJ_ROUTINE:
            return fma_routines_list (optc, options);

        case OBJ_GLOBAL:
            return fma_globals_list (optc, options);

        case OBJ_JOB:
            return fma_jobs_list (optc, options);

        default:
            fprintf (stderr, "fmadm:  'list' is an invalid action for '%s'\n", obj_str);
            return 1;

    }


} /* fm_list() */

int fm_examine (short object, int optc, char **options)
{

    switch (object) {

        case OBJ_ROUTINE:
            return fma_routines_examine (optc, options);

        case OBJ_GLOBAL:
            return fma_globals_examine (optc, options);

        case OBJ_JOB:
            return fma_jobs_examine (optc, options);

        case OBJ_JOURNAL:
            return fma_journals_examine (optc, options);
            
        default:
            fprintf (stderr, "fmadm:  'examine' is an invalid action for '%s'\n", obj_str);
            return 1;

    }

} /* fm_examine() */

int fm_verify (short object, int optc, char **options)
{

    switch (object) {

        case OBJ_GLOBAL:
            return fma_globals_verify (optc, options);
        
        default:
            fprintf (stderr, "fmadm:  'examine' is an invalid action for '%s'\n", obj_str);
            return 1;

    }

} /* fm_verify() */ 

int fm_compact (short object, int optc, char **options)
{

    switch (object) {

        default:
            fprintf (stderr, "fmadm:  'compact' is an invalid action for '%s'\n", obj_str);
            return 1;

    }

} /* fm_compact() */

int fm_repair (short object, int optc, char **options)
{

    switch (object) {

        default:
            fprintf (stderr, "fmadm:  'repair' is an invalid action for '%s'\n", obj_str);
            return 1;

    }

} /* fm_repair() */

int fm_create (short object, int optc, char **options)
{

    switch (object) {

        default:
            fprintf (stderr, "fmadm:  'create' is an invalid action for '%s'\n", obj_str);
            return 1;

    }
} /* fm_create() */

int fm_remove (short object, int optc, char **options)
{

    switch (object) {

        case OBJ_JOB:
            return fma_jobs_remove (optc, options);
        
        case OBJ_LOCK:
            return fma_locks_remove (optc, options);

        case OBJ_ROUTINE:
            return fma_routines_remove (optc, options);

        case OBJ_GLOBAL:
            return fma_globals_remove (optc, options);

        default:
            fprintf (stderr, "fmadm:  'remove' is an invalid action for '%s'\n", obj_str);
            return 1;

    }

} /* fm_remove() */

int fm_import (short object, int optc, char **options)
{

    switch (object) {

        case OBJ_ROUTINE: 
            return fma_routines_import (optc, options);

        default:
            fprintf (stderr, "fmadm:  'import' is an invalid action for '%s'\n", obj_str);
            return 1;

    }

} /* fm_import() */

int fm_export (short object, int optc, char **options)
{

    switch (object) {

        case OBJ_ROUTINE: 
            return fma_routines_export (optc, options);

        default:
            fprintf (stderr, "fmadm:  'export' is an invalid action for '%s'\n", obj_str);
            return 1;

    }

} /* fm_export() */

int fm_backup (short object, int optc, char **options)
{

    switch (object) {

        case OBJ_ROUTINE: 
            return fma_routines_backup (optc, options);

        default:
            fprintf (stderr, "fmadm:  'backup' is an invalid action for '%s'\n", obj_str);
            return 1;

    }

} /* fm_backup() */

int fm_restore (short object, int optc, char **options)
{

    switch (object) {

        case OBJ_JOURNAL:
            return fma_journals_restore (optc, options);
        
        default:
            fprintf (stderr, "fmadm:  'restore' is an invalid action for '%s'\n", obj_str);
            return 1;

    }

} /* fm_restore() */

int fm_migrate (short object, int optc, char **options)
{

    switch (object) {

        default:
            fprintf (stderr, "fmadm:  'migrate' is an invalid action for '%s'\n", obj_str);
            return 1;

    }

} /* fm_migrate() */

int fm_edit (short object, int optc, char **options)
{

    switch (object) {

        case OBJ_ROUTINE:
            return fma_routines_edit (optc, options);

            /*case OBJ_GLOBAL:
            return fma_globals_edit (optc, options);
            */
            
        default:
            fprintf (stderr, "fmadm:  'edit' is an invalid action for '%s'\n", obj_str);
            return 1;

    }

} /* fm_edit() */

void fm_checkperms(void)
{

} /* fm_checkperms() */


void fm_reconfigure(void)
{
    char config_backup[4096];
    char vers[4096];
    
    int retval;   
    
    if (geteuid () != 0) {
        fprintf (stderr, "fmadm:  not superuser\n");
        exit (1);
    }
    
    snprintf (config_backup, 4095, "%s.orig", config_file);

    fprintf (stderr, "fmadm:  reconfiguring FreeM with system defaults for %s...\n", FREEM_VERSION_CSTR);
    fprintf (stderr, "fmadm:  backing up %s to %s...\t", config_file, config_backup);    

    retval = rename (config_file, config_backup);

    if (retval == 0) {
	fprintf (stderr, "[OK]\n\n");
	
	fm_configure ();

	fprintf (stderr, "\n\nYou may wish to edit %s if site-specific changes were made to the original FreeM configuration.\n", config_file);
	exit (0);
    }
    else {
	fprintf (stderr, "[FAIL (%s)]\n", strerror (errno));
	exit (1);
    }
    
} /* fm_reconfigure() */


void fm_configure (void)
{

    char sysrtn[4096];
    char sysgbl[4096];
    char usrrtn[4096];
    char usrgbl[4096];

    char locktab[4096];
    char zalloctab[4096];
    char jnlfile[4096];
    char jnlmode[4];
    char jnlhostid[4096];    
    char jnlcut[4096];
    char hostid[4096];

    char confbase[4096];
    char envbase[4096];

    char nsbase[4096];
    
    char buf[4096];
    FILE *fp;

    struct stat etcstat;
    int stat_result;
    
    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 (jnlmode, 3, "on");
    snprintf (jnlhostid, 4095, "DEFAULT");
    snprintf (jnlcut, 4095, "4294967000");
    
    if (geteuid () != 0) {
        fprintf (stderr, "fmadm:  not superuser\n");
        exit (1);
    }
    
    if (file_exists (config_file)) {
        fprintf (stderr, "fmadm:  '%s' already exists.\n\n", config_file);
        fprintf (stderr, "'fmadm configure' may only be used on a fresh installation of FreeM.\n");
        exit (1);
    }


    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);

#if defined(__OS2__)
    {
        char srcfile[PATHLEN];
        char dstfile[PATHLEN];        
        
        snprintf (srcfile, PATHLEN, "%s/bin/freem.exe", PREFIX);
        snprintf (dstfile, PATHLEN, "%s/bin/freemd.exe", PREFIX);

        unlink (dstfile);
        
        fprintf (stderr, "fmadm:  running on OS/2; will copy %s to %s\n", srcfile, dstfile);
        
        if (DosCopy (srcfile, dstfile, 1) != 0) {
            fprintf (stderr, "fmadm:  fatal error copying %s to %s\n", srcfile, dstfile);
            exit (1);
        }

        chmod (dstfile, 0755);
    }
#else
    fprintf (stderr, "fmadm:  not running on OS/2\n");
#endif
    
    printf ("\nFreeM Initial Configuration\n");
    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);    
    
    /* check for existence of needed directories */
    if (stat (SYSCONFDIR, &etcstat) == -1) {
	fprintf (stderr, "fmadm:  creating %s\n", SYSCONFDIR);
	mkdir (SYSCONFDIR, 0755);
    }

    if (stat (confbase, &etcstat) == -1) {
        fprintf (stderr, "fmadm:  creating %s\n", confbase);
        mkdir (confbase, 0755);
    }

    if (stat (envbase, &etcstat) == -1) {
        fprintf (stderr, "fmadm:  creating %s\n", envbase);
        mkdir (envbase, 0755);
    }

    if (stat (nsbase, &etcstat) == -1) {
        fprintf (stderr, "fmadm:  creating %s\n", nsbase);
        mkdir (nsbase, 0755);
    }

   

    if (strcmp (fma_environment, "DEFAULT") != 0) {

        DIR *dir;
        struct dirent *ent;
        char src_dir[4096];
        char dest_dir[4096];

        snprintf (src_dir, 4095, "%s/freem/DEFAULT/SYSTEM/routines", LOCALSTATEDIR);
        snprintf (dest_dir, 4095, "%s/freem/%s/SYSTEM/routines", LOCALSTATEDIR, fma_environment);
        
        fprintf (stderr, "fmadm:  populating new environment '%s'\n", fma_environment);
        
        snprintf (buf, 4095, "%s/freem/%s/SYSTEM", LOCALSTATEDIR, fma_environment);
        mkdir (buf, 0755);

        snprintf (buf, 4095, "%s/freem/%s/USER", LOCALSTATEDIR, fma_environment);
        mkdir (buf, 0755);

        snprintf (buf, 4095, "%s/freem/%s/SYSTEM/routines", LOCALSTATEDIR, fma_environment);
        mkdir (buf, 0755);

        snprintf (buf, 4095, "%s/freem/%s/USER/globals", LOCALSTATEDIR, fma_environment);
        mkdir (buf, 0755);

        snprintf (buf, 4095, "%s/freem/%s/SYSTEM/globals", LOCALSTATEDIR, fma_environment);
        mkdir (buf, 0755);

        snprintf (buf, 4095, "%s/freem/%s/USER/routines", LOCALSTATEDIR, fma_environment);
        mkdir (buf, 0755);

        fprintf (stderr, "fmadm:  copying 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);
            exit (1);
        }

        while ((ent = readdir (dir)) != NULL) {
            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);
                
                snprintf (infile, 4095, "%s/%s", src_dir, ent->d_name);
                snprintf (outfile, 4095, "%s/%s", dest_dir, ent->d_name);

                if (cp (outfile, infile) != 0) {
                    fprintf (stderr, "fmadm:  failure copying %s to %s\n", infile, outfile);
                }

            }
            
        }
            
        
    }
    
   
    fp = fopen (config_file, "a+");
    

    printf ("Creating %s... ", config_file); 
    
    snprintf (buf, 4095, "[SYSTEM]");
    fm_write (fp, buf);

    snprintf (buf, 4095, "root=%s/freem/%s/SYSTEM", LOCALSTATEDIR, fma_environment);
    fm_write (fp, buf);

    snprintf (buf, 4095, "routines_path=%s", sysrtn);
    fm_write (fp, buf);

    snprintf (buf, 4095, "globals_path=%s", sysgbl);
    fm_write (fp, buf);

    snprintf (buf, 4095, "journal_file=%s", jnlfile);
    fm_write (fp, buf);

    snprintf (buf, 4095, "journal_mode=%s", jnlmode);
    fm_write (fp, buf);

    snprintf (buf, 4095, "journal_host_id=%s", jnlhostid);
    fm_write (fp, buf);

    snprintf (buf, 4095, "journal_cut_threshold=%s", jnlcut);
    fm_write (fp, buf);

    snprintf (buf, 4095, "zdate_format=%%x");
    fm_write (fp, buf);

    snprintf (buf, 4095, "ztime_format=%%X");
    fm_write (fp, buf);
    
    snprintf (buf, 4095, "\n[USER]");
    fm_write (fp, buf);

    snprintf (buf, 4095, "root=%s/freem/%s/USER", LOCALSTATEDIR, fma_environment);
    fm_write (fp, buf);

    snprintf (buf, 4095, "routines_path=%s", usrrtn);
    fm_write (fp, buf);

    snprintf (buf, 4095, "globals_path=%s", usrgbl);
    fm_write (fp, buf);
    
    
    fclose (fp);

    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);
    printf (" USER routines:                  %s\n", usrrtn);
    printf (" SYSTEM globals:                 %s\n", sysgbl);
    printf (" SYSTEM routines:                %s\n", sysrtn);
    printf (" After-image journal:            %s [%s]\n", jnlfile, jnlmode);
    printf (" Journal cut threshold:          %s bytes\n", jnlcut);
    printf (" Distributed journaling host ID: %s\n", jnlhostid);

    
} /* fm_configure */

void fm_write (FILE *file, char *buf)
{
    fprintf (file, "%s\n", buf);
}

void fm_sig_attach (int sig, void *handler)
{
    struct sigaction act;

    act.sa_handler = handler;
    sigaction (sig, &act, NULL);
    
}

void fm_sig_init (void)
{
    sig_attach (SIGINT, &fm_on_sigint);
    sig_attach (SIGTERM, &fm_on_sigterm);
}

void fm_on_sigint (void)
{
    fprintf (stderr, "\nfmadm:  caught SIGINT\n");
    fmadm_exit (0);
}

void fm_on_sigterm (void)
{
    fprintf (stderr, "\nfmadm:  caught SIGTERM\n");
    fmadm_exit (0);
}

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>