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>