File:  [Coherent Logic Development] / freem / src / fma_routines.c
Revision 1.5: download - view: text, annotated - select for diffs
Sun Apr 13 04:22:43 2025 UTC (3 months, 2 weeks ago) by snw
Branches: MAIN
CVS tags: HEAD
Fix snprintf calls

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

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