Annotation of freem/src/fma_routines.c, revision 1.5

1.1       snw         1: /*
1.5     ! snw         2:  *   $Id: fma_routines.c,v 1.4 2025/03/22 18:43:54 snw Exp $
1.1       snw         3:  *    fmadm - routines
                      4:  *
                      5:  *  
1.2       snw         6:  *   Author: Serena Willis <snw@coherent-logic.com>
1.1       snw         7:  *    Copyright (C) 1998 MUG Deutschland
1.3       snw         8:  *    Copyright (C) 2020, 2023, 2025 Coherent Logic Development LLC
1.1       snw         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:  *
1.4       snw        26:  *   $Log: fma_routines.c,v $
1.5     ! snw        27:  *   Revision 1.4  2025/03/22 18:43:54  snw
        !            28:  *   Make STRLEN 255 chars and add BIGSTR macro for larger buffers
        !            29:  *
1.4       snw        30:  *   Revision 1.3  2025/03/09 19:14:25  snw
                     31:  *   First phase of REUSE compliance and header reformat
                     32:  *
1.3       snw        33:  *
                     34:  * SPDX-FileCopyrightText:  (C) 2025 Coherent Logic Development LLC
                     35:  * SPDX-License-Identifier: AGPL-3.0-or-later
1.1       snw        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: 
1.4       snw        62:     char filename[PATHLEN];
1.1       snw        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: 
1.4       snw        81:         strncpy (filename, ent->d_name, PATHLEN - 1);
1.1       snw        82: 
                     83:         rtnname = strtok (filename, ".");
                     84:         rtnext = strtok (NULL, ".");
                     85: 
1.4       snw        86:         if (rtnext != NULL && strncmp (rtnext, "m", PATHLEN - 1) == 0) {
1.1       snw        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;
1.4       snw       103:     char rpath[PATHLEN];
1.1       snw       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: 
1.4       snw       124:     snprintf (rpath, PATHLEN - 1, "%s/%s.m", fma_routine_path, opts[fma_base_opt]);
1.1       snw       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;
1.4       snw       150:     char rpath[PATHLEN];
1.1       snw       151:     /* char *editor; */
                    152: 
                    153:     if (optc < fma_min_args) {
                    154:         fprintf (stderr, "fmadm:  must supply routine name\n");
                    155:         return 1;
                    156:     }
                    157: 
1.4       snw       158:     snprintf (rpath, PATHLEN - 1, "%s/%s.m", fma_routine_path, opts[fma_base_opt]);
1.1       snw       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];
1.4       snw       185:     char backup_filename[PATHLEN];
1.1       snw       186:     char dtstamp[STRLEN];
1.4       snw       187:     char bup_path[PATHLEN];
1.1       snw       188: 
                    189:     buf = gmtime (&t);
                    190: 
                    191:     if (optc > 1) {
1.4       snw       192:         strncpy (bup_path, opts[fma_base_opt], PATHLEN - 1);
1.1       snw       193:     }
                    194:     else {
1.4       snw       195:         strncpy (bup_path, "/tmp", PATHLEN - 1);
1.1       snw       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);
1.4       snw       199:     snprintf (backup_filename, PATHLEN - 1, "%s/freem-routines-backup-%s-%s.tar", bup_path, fma_namespace, dtstamp);
1.1       snw       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: 
1.4       snw       272:     if (strncmp (fma_namespace, "SYSTEM", PATHLEN - 1) != 0) {
1.1       snw       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: 
1.5     ! snw       361:                     snprintf(roufile, PATH_MAX - 1, "%s/%s.m", pct_rtn_path, parsed_line);
1.1       snw       362:                     break;
                    363: 
                    364:                 default:
                    365:                     usr_loaded++;
                    366: 
1.5     ! snw       367:                     snprintf(roufile, PATH_MAX - 1, "%s/%s.m", usr_rtn_path, parsed_line);
1.1       snw       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;
1.4       snw       409:     char output_file[PATHLEN];
                    410:     char routine_spec[PATHLEN];
                    411:     char filename[PATHLEN];
1.1       snw       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) {
1.4       snw       426:         strncpy (routine_spec, "*", PATHLEN - 1);
1.1       snw       427:     }
                    428: 
1.4       snw       429:     strncpy (output_file, opts[1], PATHLEN - 1);
                    430:     strncpy (routine_spec, opts[2], PATHLEN - 1);
1.1       snw       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: 
1.4       snw       476:             strncpy (filename, ent->d_name, PATHLEN - 1);
1.1       snw       477: 
                    478:             rtnname = strtok (filename, ".");
                    479:             rtnext = strtok (NULL, ".");
                    480: 
1.4       snw       481:             if (rtnext != NULL && strncmp (rtnext, "m", PATHLEN - 1) == 0) {
1.1       snw       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;
1.4       snw       510:     char rtnfile[PATHLEN];
1.1       snw       511:     char line[FM_STR_MAX];
                    512: 
1.4       snw       513:     snprintf (rtnfile, PATHLEN - 1, "%s/%s.m", fma_routine_path, rtn_name);
1.1       snw       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:     
1.4       snw       545:     char rpath[PATHLEN];
1.1       snw       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: 
1.4       snw       560:         snprintf (rpath, PATHLEN - 1, "%s/%s.m", fma_routine_path, opts[i]);
1.1       snw       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>