/*
* $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>