/*
* $Id: fma_routines.c,v 1.4 2025/03/22 18:43:54 snw Exp $
* fmadm - routines
*
*
* 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: fma_routines.c,v $
* Revision 1.4 2025/03/22 18:43:54 snw
* Make STRLEN 255 chars and add BIGSTR macro for larger buffers
*
* Revision 1.3 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <errno.h>
#include "fmadm.h"
#include "iniconf.h"
int fma_do_export (FILE *out, char *rtn_name);
char *fma_trim_string(char *str);
int fma_routines_list (int optc, char **opts)
{
DIR *dir;
struct dirent *ent;
char filename[PATHLEN];
char *rtnname;
char *rtnext;
int ct = 0;
printf ("\nFreeM Routine Listing\n");
printf ("---------------------\n\n");
printf ("Namespace: %s\n", fma_namespace);
printf ("Routine Path: %s\n\n", fma_routine_path);
if ((dir = opendir (fma_routine_path)) == NULL) {
fprintf (stderr, "fmadm: could not open routine directory %s\n", fma_routine_path);
return 1;
}
while ((ent = readdir (dir)) != NULL) {
strncpy (filename, ent->d_name, PATHLEN - 1);
rtnname = strtok (filename, ".");
rtnext = strtok (NULL, ".");
if (rtnext != NULL && strncmp (rtnext, "m", PATHLEN - 1) == 0) {
printf (" %s\n", rtnname);
ct++;
}
}
printf ("\n\n - %d routines found\n\n", ct);
closedir (dir);
return 0;
}
int fma_routines_edit (int optc, char **opts)
{
FILE *fp;
char rpath[PATHLEN];
char ecmd[STRLEN];
char *editor;
if (optc < fma_min_args) {
fprintf (stderr, "fmadm: must supply routine name\n");
return 1;
}
if ((editor = getenv("EDITOR")) == NULL) {
if ((editor = (char *) malloc (3 * sizeof (char))) == NULL) {
fprintf (stderr, "fmadm: could not acquire memory\n");
return 1;
}
strncpy (editor, "vi", 3);
}
snprintf (rpath, PATHLEN - 1, "%s/%s.m", fma_routine_path, opts[fma_base_opt]);
if (file_exists (rpath) == FALSE) {
if ((fp = fopen (rpath, "w")) == NULL) {
fprintf (stderr, "fmadm: error %d creating routine %s (%s)\n", errno, opts[1], strerror (errno));
return 1;
}
fprintf (fp, "%s ; Created by FreeM Administrator\n QUIT\n", opts[1]);
fclose (fp);
}
snprintf (ecmd, STRLEN - 1, "%s %s", editor, rpath);
system (ecmd);
return 0;
}
int fma_routines_examine (int optc, char **opts)
{
FILE *fp;
char c;
char rpath[PATHLEN];
/* char *editor; */
if (optc < fma_min_args) {
fprintf (stderr, "fmadm: must supply routine name\n");
return 1;
}
snprintf (rpath, PATHLEN - 1, "%s/%s.m", fma_routine_path, opts[fma_base_opt]);
if (file_exists (rpath) == FALSE) {
fprintf (stderr, "fmadm: routine %s does not exist in namespace %s\n", opts[1], fma_namespace);
return 1;
}
if ((fp = fopen (rpath, "r")) == NULL) {
fprintf (stderr, "fmadm: could not open routine %s\n", opts[1]);
return 1;
}
while ((c = fgetc (fp)) != EOF) putchar (c);
fclose (fp);
putchar ('\n');
return 0;
}
int fma_routines_backup (int optc, char **opts)
{
time_t t = time (NULL);
struct tm *buf;
char rcmd[STRLEN];
char backup_filename[PATHLEN];
char dtstamp[STRLEN];
char bup_path[PATHLEN];
buf = gmtime (&t);
if (optc > 1) {
strncpy (bup_path, opts[fma_base_opt], PATHLEN - 1);
}
else {
strncpy (bup_path, "/tmp", PATHLEN - 1);
}
snprintf (dtstamp, STRLEN - 1, "%d%02d%02d%02d%02d%02d", buf->tm_year, buf->tm_mon, buf->tm_mday, buf->tm_hour, buf->tm_min, buf->tm_sec);
snprintf (backup_filename, PATHLEN - 1, "%s/freem-routines-backup-%s-%s.tar", bup_path, fma_namespace, dtstamp);
printf ("\nFreeM Routine Backup\n");
printf ("--------------------\n\n");
printf ("Namespace: %s\n", fma_namespace);
printf ("Routine Path: %s\n", fma_routine_path);
printf ("Backup Location: %s\n", bup_path);
printf ("Backup Filename: %s\n\n", backup_filename);
snprintf (rcmd, STRLEN - 1, "tar cvf %s %s/*.m", backup_filename, fma_routine_path);
system (rcmd);
printf ("\n\nBackup completed.\n\n");
return 0;
}
int fma_routines_restore (int optc, char **opts)
{
return 0;
}
char *fma_trim_string(char *str)
{
char *end;
while (isspace ((unsigned char) *str)) str++;
if (*str == 0) return str;
end = str + strlen (str) - 1;
while (end > str && isspace ((unsigned char) *end)) end--;
end[1] = '\0';
return str;
}
int fma_routines_import (int optc, char **opts)
{
int usr_loaded = 0;
int pct_loaded = 0;
int next_routine_flag = FALSE;
int rtn_open = FALSE;
int rtn_overwrite = TRUE;
long ln = 0;
char pct_rtn_path[4096];
char usr_rtn_path[4096];
char namespace[4096];
char roufile[4096];
char line[STRLEN];
char *trimmed_line;
char filename[4096];
FILE *archive = NULL;
FILE *rtn = NULL;
char *parsed_line;
strncpy (namespace, fma_namespace, 512 - 1);
strncpy (filename, opts[fma_base_opt], 4096 - 1);
if (optc < fma_min_args) {
fprintf (stderr, "usage: fmadm import routine <namespace> <rsav-file>\n");
return 1;
}
if (strncmp (fma_namespace, "SYSTEM", PATHLEN - 1) != 0) {
if (get_conf ("SYSTEM", "routines_path", pct_rtn_path) == FALSE) {
fprintf (stderr, "fmadm: could not determine percent routine access path from configuration for namespace '%s'.\n", namespace);
return 1;
}
}
else {
strncpy (pct_rtn_path, fma_routine_path, 4096 - 1);
}
if (get_conf (namespace, "routines_path", usr_rtn_path) == FALSE) {
fprintf (stderr, "fmadm: could not determine user routine access path from configuration for namespace '%s'.\n", namespace);
return 1;
}
if ((archive = fopen (filename, "r")) == NULL) {
fprintf (stderr, "fmadm: could not open routine archive '%s'.\n", filename);
return 1;
}
printf ("\nFreeM Routine Import\n");
printf ("--------------------\n\n");
printf ("Namespace: %s\n", fma_namespace);
printf ("Archive: %s\n", filename);
printf ("Routine Path: %s\n", usr_rtn_path);
printf ("%% Routine Path: %s\n\n", pct_rtn_path);
/* read routine archive line-by-line */
while (fgets(line, STRLEN - 1, archive) != NULL) {
if (line[strlen(line) - 1] == '\n') line[strlen(line) - 1] = '\0';
ln++;
if ((ln == 1) || (ln == 2)) {
printf("%s\n", line);
continue;
}
if (ln == 3) {
next_routine_flag = TRUE;
}
trimmed_line = strdup (line);
if (strcmp (fma_trim_string (trimmed_line), "") == 0) {
next_routine_flag = TRUE;
if(rtn_open == TRUE) {
fclose(rtn);
rtn_open = FALSE;
}
continue;
}
if(next_routine_flag == TRUE) {
next_routine_flag = FALSE;
parsed_line = strtok (line, "^");
if((!isalpha(line[0])) && (line[0] != '%')) {
if(rtn_open == TRUE) {
fclose(rtn);
rtn_open = FALSE;
}
continue;
}
printf(" %s\n", parsed_line);
switch(line[0]) {
case '%':
pct_loaded++;
snprintf(roufile, PATH_MAX, "%s/%s.m", pct_rtn_path, parsed_line);
break;
default:
usr_loaded++;
snprintf(roufile, PATH_MAX, "%s/%s.m", usr_rtn_path, parsed_line);
break;
}
if((file_exists(roufile) == TRUE) && (rtn_overwrite == FALSE)) {
fprintf(stdout, "fmadm: routine file '%s' already exists. Will not overwrite.\n", roufile);
fclose (archive);
return 1;
}
if((rtn = fopen(roufile, "w")) == NULL) {
fprintf(stdout, "fmadm: could not open routine file '%s'.\n", roufile);
return 1;
}
else {
rtn_open = TRUE;
}
}
else {
if(rtn_open == TRUE) fprintf(rtn, "%s\n", line);
}
}
printf("\n - loaded %d user routines and %d percent routines (%d total)\n\n", usr_loaded, pct_loaded, usr_loaded + pct_loaded);
fclose (archive);
return 0;
}
int fma_routines_export (int optc, char **opts)
{
FILE *out; /* output file handle */
DIR *dir; /* namespace directory */
struct dirent *ent;
char output_file[PATHLEN];
char routine_spec[PATHLEN];
char filename[PATHLEN];
char *rtnname;
char *rtnext;
int i;
int ct = 0;
if (optc < fma_min_args) {
fprintf (stderr, "usage: fmadm export routine <namespace> <output-file> [routine1 routine2... routineN]\n");
return 1;
}
/* if routines aren't listed, assume we should export entire namespace */
if (optc == fma_min_args) {
strncpy (routine_spec, "*", PATHLEN - 1);
}
strncpy (output_file, opts[1], PATHLEN - 1);
strncpy (routine_spec, opts[2], PATHLEN - 1);
if (file_exists (output_file) == TRUE) {
fprintf (stderr, "fmadm: output file %s already exists\n", output_file);
return 1;
}
if ((out = fopen(output_file, "w")) == NULL) {
fprintf (stderr, "fmadm: could not open output file %s for writing\n", output_file);
return 1;
}
printf ("\nFreeM Routine Export\n");
printf ("--------------------\n\n");
printf ("Namespace: %s\n", fma_namespace);
printf ("Routine Path: %s\n", fma_routine_path);
printf ("Output File: %s\n", output_file);
printf ("Routines Selected: ");
if (optc == 2) {
printf ("[ENTIRE NAMESPACE]\n\n");
}
else {
for (i = 2; i < optc; i++) {
printf ("%s ", opts[i]);
}
printf ("\n\n");
}
fprintf (out, "Routines\n");
if (optc == 2) {
/* export entire namespace */
if ((dir = opendir (fma_routine_path)) == NULL) {
fprintf (stderr, "fmadm: could not open routine directory %s\n", fma_routine_path);
fclose (out);
return 1;
}
while ((ent = readdir (dir)) != NULL) {
strncpy (filename, ent->d_name, PATHLEN - 1);
rtnname = strtok (filename, ".");
rtnext = strtok (NULL, ".");
if (rtnext != NULL && strncmp (rtnext, "m", PATHLEN - 1) == 0) {
ct += fma_do_export (out, rtnname);
}
}
closedir (dir);
}
else {
/* export only selected routines */
for (i = fma_base_opt + 1; i < optc; i++) {
ct += fma_do_export (out, opts[i]);
}
}
printf ("\n\n - %d routines exported\n\n", ct);
fclose (out);
return 0;
}
int fma_do_export (FILE *out, char *rtn_name)
{
FILE *in;
char rtnfile[PATHLEN];
char line[FM_STR_MAX];
snprintf (rtnfile, PATHLEN - 1, "%s/%s.m", fma_routine_path, rtn_name);
printf (" Exporting %-10s\t", rtn_name);
if ((in = fopen (rtnfile, "r")) == NULL) {
printf ("[FAIL]\n");
return 0;
}
fprintf (out, "\n%s\n", rtn_name);
while (fgets (line, FM_STR_MAX, in) != NULL) {
fprintf (out, "%s", line);
}
printf ("[OK]\n");
fprintf (out, "\n");
fclose (in);
return 1;
}
int fma_routines_create (int optc, char **opts)
{
return 0;
}
int fma_routines_remove (int optc, char **opts)
{
char rpath[PATHLEN];
int i;
int ct = 0;
int er = 0;
int tot = 0;
printf ("\nFreeM Routine Removal\n");
printf ("---------------------\n\n");
printf ("Namespace: %s\n", fma_namespace);
printf ("Routine Path: %s\n\n", fma_routine_path);
for (i = fma_base_opt; i < optc; i++) {
printf ("%-10s\t", opts[i]);
snprintf (rpath, PATHLEN - 1, "%s/%s.m", fma_routine_path, opts[i]);
if (unlink (rpath) == -1) {
printf ("[FAIL]\n");
er++;
}
else {
printf ("[OK]\n");
ct++;
}
tot++;
}
printf ("\nRemoved %d routines [%d errors/%d attempted]\n\n", ct, er, tot);
return 0;
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>