File:  [Coherent Logic Development] / freem / src / fma_routines.c
Revision 1.3: download - view: text, annotated - select for diffs
Sun Mar 9 19:14:25 2025 UTC (7 months, 3 weeks ago) by snw
Branches: MAIN
CVS tags: v0-62-1, v0-62-0, HEAD
First phase of REUSE compliance and header reformat

    1: /*
    2:  *   $Id: fma_routines.c,v 1.3 2025/03/09 19:14:25 snw Exp $
    3:  *    fmadm - routines
    4:  *
    5:  *  
    6:  *   Author: Serena Willis <snw@coherent-logic.com>
    7:  *    Copyright (C) 1998 MUG Deutschland
    8:  *    Copyright (C) 2020, 2023, 2025 Coherent Logic Development LLC
    9:  *
   10:  *
   11:  *   This file is part of FreeM.
   12:  *
   13:  *   FreeM is free software: you can redistribute it and/or modify
   14:  *   it under the terms of the GNU Affero Public License as published by
   15:  *   the Free Software Foundation, either version 3 of the License, or
   16:  *   (at your option) any later version.
   17:  *
   18:  *   FreeM is distributed in the hope that it will be useful,
   19:  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   20:  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   21:  *   GNU Affero Public License for more details.
   22:  *
   23:  *   You should have received a copy of the GNU Affero Public License
   24:  *   along with FreeM.  If not, see <https://www.gnu.org/licenses/>.
   25:  *
   26:  *   $Log: fma_routines.c,v $
   27:  *   Revision 1.3  2025/03/09 19:14:25  snw
   28:  *   First phase of REUSE compliance and header reformat
   29:  *
   30:  *
   31:  * SPDX-FileCopyrightText:  (C) 2025 Coherent Logic Development LLC
   32:  * SPDX-License-Identifier: AGPL-3.0-or-later
   33:  **/
   34: 
   35: #include <stdio.h>
   36: #include <stdlib.h>
   37: #include <string.h>
   38: #include <dirent.h>
   39: #include <stdlib.h>
   40: #include <time.h>
   41: #include <unistd.h>
   42: #include <sys/types.h>
   43: #include <sys/stat.h>
   44: #include <ctype.h>
   45: #include <errno.h>
   46: 
   47: #include "fmadm.h"
   48: #include "iniconf.h"
   49: 
   50: int fma_do_export (FILE *out, char *rtn_name);
   51: char *fma_trim_string(char *str);
   52: 
   53: int fma_routines_list (int optc, char **opts)
   54: {
   55: 
   56:     DIR *dir;
   57:     struct dirent *ent;
   58: 
   59:     char filename[STRLEN];
   60:     char *rtnname;
   61:     char *rtnext;
   62: 
   63:     int ct = 0;
   64: 
   65:     printf ("\nFreeM Routine Listing\n");
   66:     printf ("---------------------\n\n");
   67: 
   68:     printf ("Namespace:     %s\n", fma_namespace);
   69:     printf ("Routine Path:  %s\n\n", fma_routine_path);
   70: 
   71:     if ((dir = opendir (fma_routine_path)) == NULL) {
   72:         fprintf (stderr, "fmadm:  could not open routine directory %s\n", fma_routine_path);
   73:         return 1;
   74:     }
   75: 
   76:     while ((ent = readdir (dir)) != NULL) {
   77: 
   78:         strncpy (filename, ent->d_name, STRLEN - 1);
   79: 
   80:         rtnname = strtok (filename, ".");
   81:         rtnext = strtok (NULL, ".");
   82: 
   83:         if (rtnext != NULL && strncmp (rtnext, "m", STRLEN - 1) == 0) {
   84:             printf (" %s\n", rtnname);
   85:             ct++;
   86:         }
   87: 
   88:     }
   89: 
   90:     printf ("\n\n    - %d routines found\n\n", ct);
   91:     closedir (dir);
   92: 
   93:     return 0;
   94: 
   95: }
   96: 
   97: int fma_routines_edit (int optc, char **opts)
   98: {
   99:     FILE *fp;
  100:     char rpath[STRLEN];
  101:     char ecmd[STRLEN];
  102:     char *editor;
  103: 
  104:     if (optc < fma_min_args) {
  105:         fprintf (stderr, "fmadm:  must supply routine name\n");
  106:         return 1;
  107:     }
  108: 
  109: 
  110:     if ((editor = getenv("EDITOR")) == NULL) {
  111:         
  112:         if ((editor = (char *) malloc (3 * sizeof (char))) == NULL) {
  113:             fprintf (stderr, "fmadm:  could not acquire memory\n");
  114:             return 1;
  115:         }
  116:         
  117:         strncpy (editor, "vi", 3);
  118: 
  119:     }
  120: 
  121:     snprintf (rpath, STRLEN - 1, "%s/%s.m", fma_routine_path, opts[fma_base_opt]);
  122: 
  123:     if (file_exists (rpath) == FALSE) {
  124:         if ((fp = fopen (rpath, "w")) == NULL) {
  125:             fprintf (stderr, "fmadm:  error %d creating routine %s (%s)\n", errno, opts[1], strerror (errno));
  126: 
  127:             return 1;
  128:         }
  129: 
  130:         fprintf (fp, "%s ; Created by FreeM Administrator\n    QUIT\n", opts[1]);
  131:         fclose (fp);
  132:        
  133:     }
  134: 
  135:     snprintf (ecmd, STRLEN - 1, "%s %s", editor, rpath);
  136:     system (ecmd);
  137: 
  138:     return 0;
  139: 
  140: }
  141: 
  142: int fma_routines_examine (int optc, char **opts)
  143: {
  144: 
  145:     FILE *fp;
  146:     char c;
  147:     char rpath[STRLEN];
  148:     /* char *editor; */
  149: 
  150:     if (optc < fma_min_args) {
  151:         fprintf (stderr, "fmadm:  must supply routine name\n");
  152:         return 1;
  153:     }
  154: 
  155:     snprintf (rpath, STRLEN - 1, "%s/%s.m", fma_routine_path, opts[fma_base_opt]);
  156: 
  157:     if (file_exists (rpath) == FALSE) {
  158:         fprintf (stderr, "fmadm:  routine %s does not exist in namespace %s\n", opts[1], fma_namespace);
  159:         return 1;
  160:     }
  161: 
  162:     if ((fp = fopen (rpath, "r")) == NULL) {
  163:         fprintf (stderr, "fmadm:  could not open routine %s\n", opts[1]);        
  164:         return 1;
  165:     }
  166: 
  167:     while ((c = fgetc (fp)) != EOF) putchar (c);
  168: 
  169:     fclose (fp);
  170: 
  171:     putchar ('\n');
  172: 
  173:     return 0;
  174: 
  175: }
  176: 
  177: int fma_routines_backup (int optc, char **opts)
  178: {
  179:     time_t t = time (NULL);
  180:     struct tm *buf;
  181:     char rcmd[STRLEN];
  182:     char backup_filename[STRLEN];
  183:     char dtstamp[STRLEN];
  184:     char bup_path[STRLEN];
  185: 
  186:     buf = gmtime (&t);
  187: 
  188:     if (optc > 1) {
  189:         strncpy (bup_path, opts[fma_base_opt], STRLEN - 1);
  190:     }
  191:     else {
  192:         strncpy (bup_path, "/tmp", STRLEN - 1);
  193:     }
  194: 
  195:     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);
  196:     snprintf (backup_filename, STRLEN - 1, "%s/freem-routines-backup-%s-%s.tar", bup_path, fma_namespace, dtstamp);
  197: 
  198:     printf ("\nFreeM Routine Backup\n");
  199:     printf ("--------------------\n\n");
  200: 
  201:     printf ("Namespace:        %s\n", fma_namespace);
  202:     printf ("Routine Path:     %s\n", fma_routine_path);
  203:     printf ("Backup Location:  %s\n", bup_path);
  204:     printf ("Backup Filename:  %s\n\n", backup_filename);
  205: 
  206:     snprintf (rcmd, STRLEN - 1, "tar cvf %s %s/*.m", backup_filename, fma_routine_path);
  207:     system (rcmd);
  208: 
  209:     printf ("\n\nBackup completed.\n\n");
  210: 
  211:     return 0;
  212: 
  213: }
  214: 
  215: int fma_routines_restore (int optc, char **opts)
  216: {
  217:     return 0;
  218: }
  219: 
  220: char *fma_trim_string(char *str)
  221: {
  222: 
  223:     char *end;
  224: 
  225:     while (isspace ((unsigned char) *str)) str++;
  226: 
  227:     if (*str == 0) return str;
  228: 
  229:     end = str + strlen (str) - 1;
  230: 
  231:     while (end > str && isspace ((unsigned char) *end)) end--;
  232: 
  233:     end[1] = '\0';
  234: 
  235:     return str;
  236: 
  237: }
  238: 
  239: int fma_routines_import (int optc, char **opts)
  240: {
  241:     int usr_loaded = 0;
  242:     int pct_loaded = 0;
  243:     int next_routine_flag = FALSE;
  244:     int rtn_open = FALSE;
  245:     int rtn_overwrite = TRUE;
  246:     long ln = 0;
  247: 
  248:     char pct_rtn_path[4096];
  249:     char usr_rtn_path[4096];
  250:     char namespace[4096];
  251:     char roufile[4096];
  252:     char line[STRLEN];  
  253:     char *trimmed_line;
  254:     
  255:     char filename[4096];
  256:     FILE *archive = NULL;
  257:     FILE *rtn = NULL;
  258: 
  259:     char *parsed_line;
  260:     
  261:     strncpy (namespace, fma_namespace, 512 - 1);
  262:     strncpy (filename, opts[fma_base_opt], 4096 - 1);
  263: 
  264:     if (optc < fma_min_args) {
  265:         fprintf (stderr, "usage:  fmadm import routine <namespace> <rsav-file>\n");
  266:         return 1;
  267:     }
  268: 
  269:     if (strncmp (fma_namespace, "SYSTEM", STRLEN - 1) != 0) {
  270:         
  271:         if (get_conf ("SYSTEM", "routines_path", pct_rtn_path) == FALSE) {
  272:             fprintf (stderr, "fmadm:  could not determine percent routine access path from configuration for namespace '%s'.\n", namespace);
  273: 
  274:             return 1;
  275:         }
  276: 
  277:     }
  278:     else {
  279:         strncpy (pct_rtn_path, fma_routine_path, 4096 - 1);
  280:     }
  281: 
  282: 
  283:     if (get_conf (namespace, "routines_path", usr_rtn_path) == FALSE) {
  284:         fprintf (stderr, "fmadm:  could not determine user routine access path from configuration for namespace '%s'.\n", namespace);
  285: 
  286:         return 1;
  287:     }
  288: 
  289:     if ((archive = fopen (filename, "r")) == NULL) {
  290:         fprintf (stderr, "fmadm:  could not open routine archive '%s'.\n", filename);
  291: 
  292:         return 1;
  293:     }
  294: 
  295:     printf ("\nFreeM Routine Import\n");
  296:     printf ("--------------------\n\n");
  297:     
  298:     printf ("Namespace:        %s\n", fma_namespace);
  299:     printf ("Archive:          %s\n", filename);
  300:     printf ("Routine Path:     %s\n", usr_rtn_path);
  301:     printf ("%% Routine Path:   %s\n\n", pct_rtn_path);
  302: 
  303:     /* read routine archive line-by-line */
  304:     while (fgets(line, STRLEN - 1, archive) != NULL) {
  305: 
  306:         if (line[strlen(line) - 1] == '\n') line[strlen(line) - 1] = '\0';
  307: 
  308:         ln++;
  309: 
  310:         if ((ln == 1) || (ln == 2)) {
  311:             printf("%s\n", line);
  312:             continue;
  313:         }
  314: 
  315:         if (ln == 3) {
  316:             next_routine_flag = TRUE;
  317:         }
  318: 
  319:         trimmed_line = strdup (line);
  320:         
  321:         if (strcmp (fma_trim_string (trimmed_line), "") == 0) {
  322:             
  323:             next_routine_flag = TRUE;
  324:             
  325:             if(rtn_open == TRUE) {
  326:                 fclose(rtn);
  327:                 
  328:                 rtn_open = FALSE;
  329:             }
  330: 
  331:             continue;
  332:         }
  333:         
  334:         if(next_routine_flag == TRUE) {
  335:             
  336:             next_routine_flag = FALSE;
  337: 
  338:             parsed_line = strtok (line, "^");
  339:             
  340:             if((!isalpha(line[0])) && (line[0] != '%')) {
  341: 
  342:                 if(rtn_open == TRUE) {
  343:                     fclose(rtn);
  344:                     rtn_open = FALSE;
  345:                 }
  346: 
  347:                 continue; 
  348:             }
  349: 
  350:             printf(" %s\n", parsed_line);
  351: 
  352:             
  353:             switch(line[0]) {
  354:                 
  355:                 case '%':
  356:                     pct_loaded++;
  357: 
  358:                     snprintf(roufile, PATH_MAX, "%s/%s.m", pct_rtn_path, parsed_line);
  359:                     break;
  360: 
  361:                 default:
  362:                     usr_loaded++;
  363: 
  364:                     snprintf(roufile, PATH_MAX, "%s/%s.m", usr_rtn_path, parsed_line);
  365:                     break;
  366:             }
  367: 
  368:             if((file_exists(roufile) == TRUE) && (rtn_overwrite == FALSE)) {
  369:                 fprintf(stdout, "fmadm:  routine file '%s' already exists. Will not overwrite.\n", roufile);
  370: 
  371:                 fclose (archive);
  372:                 
  373:                 return 1;
  374:             }
  375: 
  376:             if((rtn = fopen(roufile, "w")) == NULL) {
  377:                 fprintf(stdout, "fmadm:  could not open routine file '%s'.\n", roufile);
  378: 
  379:                 return 1;
  380:             }
  381:             else {
  382:                 rtn_open = TRUE;
  383:             }
  384: 
  385:         }
  386:         else {
  387:             if(rtn_open == TRUE) fprintf(rtn, "%s\n", line);
  388:         }
  389: 
  390:     }
  391: 
  392:     printf("\n     - loaded %d user routines and %d percent routines (%d total)\n\n", usr_loaded, pct_loaded, usr_loaded + pct_loaded);
  393: 
  394:     fclose (archive);
  395:     
  396:     return 0;
  397: }
  398: 
  399: int fma_routines_export (int optc, char **opts)
  400: {
  401: 
  402:     FILE *out;      /* output file handle */
  403:     DIR *dir;       /* namespace directory */
  404:     
  405:     struct dirent *ent;
  406:     char output_file[STRLEN];
  407:     char routine_spec[STRLEN];
  408:     char filename[STRLEN];
  409:     char *rtnname;
  410:     char *rtnext;
  411:     int i;
  412: 
  413:     int ct = 0;
  414: 
  415: 
  416:     if (optc < fma_min_args) {
  417:         fprintf (stderr, "usage:  fmadm export routine <namespace> <output-file> [routine1 routine2... routineN]\n");
  418:         return 1;
  419:     }
  420: 
  421:     /* if routines aren't listed, assume we should export entire namespace */
  422:     if (optc == fma_min_args) {
  423:         strncpy (routine_spec, "*", STRLEN - 1);
  424:     }
  425: 
  426:     strncpy (output_file, opts[1], STRLEN - 1);
  427:     strncpy (routine_spec, opts[2], STRLEN - 1);
  428: 
  429:     if (file_exists (output_file) == TRUE) {
  430:         fprintf (stderr, "fmadm:  output file %s already exists\n", output_file);
  431:         return 1;
  432:     }
  433: 
  434:     if ((out = fopen(output_file, "w")) == NULL) {
  435:         fprintf (stderr, "fmadm:  could not open output file %s for writing\n", output_file);
  436:         return 1;
  437:     }
  438: 
  439: 
  440:     printf ("\nFreeM Routine Export\n");
  441:     printf ("--------------------\n\n");
  442: 
  443:     printf ("Namespace:             %s\n", fma_namespace);
  444:     printf ("Routine Path:          %s\n", fma_routine_path);
  445:     printf ("Output File:           %s\n", output_file);
  446:     printf ("Routines Selected:     ");
  447:     
  448:     if (optc == 2) {
  449:         printf ("[ENTIRE NAMESPACE]\n\n");
  450:     }
  451:     else {
  452:         for (i = 2; i < optc; i++) {
  453:             printf ("%s ", opts[i]);
  454:         }
  455: 
  456:         printf ("\n\n");
  457:     }
  458: 
  459:     fprintf (out, "Routines\n");
  460: 
  461:     if (optc == 2) {
  462: 
  463:         /* export entire namespace */
  464: 
  465:         if ((dir = opendir (fma_routine_path)) == NULL) {
  466:             fprintf (stderr, "fmadm:  could not open routine directory %s\n", fma_routine_path);
  467:             fclose (out);
  468:             return 1;
  469:         }
  470: 
  471:         while ((ent = readdir (dir)) != NULL) {
  472: 
  473:             strncpy (filename, ent->d_name, STRLEN - 1);
  474: 
  475:             rtnname = strtok (filename, ".");
  476:             rtnext = strtok (NULL, ".");
  477: 
  478:             if (rtnext != NULL && strncmp (rtnext, "m", STRLEN - 1) == 0) {
  479:                 ct += fma_do_export (out, rtnname);
  480:             }
  481: 
  482:         }
  483: 
  484:         closedir (dir);
  485: 
  486:     }
  487:     else {
  488: 
  489:         /* export only selected routines */
  490:         for (i = fma_base_opt + 1; i < optc; i++) {
  491:             ct += fma_do_export (out, opts[i]);
  492:         }
  493: 
  494:     }
  495: 
  496:     printf ("\n\n    - %d routines exported\n\n", ct);
  497: 
  498:     fclose (out);
  499:     
  500:     return 0;
  501: 
  502: }
  503: 
  504: int fma_do_export (FILE *out, char *rtn_name)
  505: {
  506:     FILE *in;
  507:     char rtnfile[STRLEN];
  508:     char line[FM_STR_MAX];
  509: 
  510:     snprintf (rtnfile, STRLEN - 1, "%s/%s.m", fma_routine_path, rtn_name);
  511: 
  512:     printf (" Exporting %-10s\t", rtn_name);
  513: 
  514:     if ((in = fopen (rtnfile, "r")) == NULL) {
  515:         printf ("[FAIL]\n");
  516:         return 0;
  517:     }
  518: 
  519:     fprintf (out, "\n%s\n", rtn_name);
  520: 
  521:     while (fgets (line, FM_STR_MAX, in) != NULL) {
  522:         fprintf (out, "%s", line);
  523:     }
  524: 
  525:     printf ("[OK]\n");
  526: 
  527:     fprintf (out, "\n");
  528: 
  529:     fclose (in);
  530: 
  531:     return 1;
  532: }
  533: 
  534: int fma_routines_create (int optc, char **opts)
  535: {
  536:     return 0;
  537: }
  538: 
  539: int fma_routines_remove (int optc, char **opts)
  540: {
  541:     
  542:     char rpath[STRLEN];
  543:     int i;
  544:     int ct = 0;
  545:     int er = 0;
  546:     int tot = 0;
  547: 
  548:     printf ("\nFreeM Routine Removal\n");
  549:     printf ("---------------------\n\n");
  550: 
  551:     printf ("Namespace:     %s\n", fma_namespace);
  552:     printf ("Routine Path:  %s\n\n", fma_routine_path);
  553: 
  554:     for (i = fma_base_opt; i < optc; i++) {
  555:         printf ("%-10s\t", opts[i]);
  556: 
  557:         snprintf (rpath, STRLEN - 1, "%s/%s.m", fma_routine_path, opts[i]);
  558: 
  559:         if (unlink (rpath) == -1) {
  560:             printf ("[FAIL]\n");
  561:             er++;
  562:         }
  563:         else {
  564:             printf ("[OK]\n");
  565:             ct++;
  566:         }
  567: 
  568:         tot++;
  569:     
  570:     }
  571: 
  572:     printf ("\nRemoved %d routines [%d errors/%d attempted]\n\n", ct, er, tot);
  573: 
  574:     return 0;
  575: 
  576: }

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