File:  [Coherent Logic Development] / freem / src / fma_routines.c
Revision 1.4: download - view: text, annotated - select for diffs
Sat Mar 22 18:43:54 2025 UTC (12 months, 1 week ago) by snw
Branches: MAIN
CVS tags: v0-63-1-rc1, v0-63-0-rc1, v0-63-0, v0-62-3, v0-62-2, HEAD
Make STRLEN 255 chars and add BIGSTR macro for larger buffers

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

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