Annotation of freem/src/fma_routines.c, revision 1.4
1.1 snw 1: /*
1.4 ! snw 2: * $Id: fma_routines.c,v 1.3 2025/03/09 19:14:25 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 $
! 27: * Revision 1.3 2025/03/09 19:14:25 snw
! 28: * First phase of REUSE compliance and header reformat
! 29: *
1.3 snw 30: *
31: * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
32: * SPDX-License-Identifier: AGPL-3.0-or-later
1.1 snw 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:
1.4 ! snw 59: char filename[PATHLEN];
1.1 snw 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:
1.4 ! snw 78: strncpy (filename, ent->d_name, PATHLEN - 1);
1.1 snw 79:
80: rtnname = strtok (filename, ".");
81: rtnext = strtok (NULL, ".");
82:
1.4 ! snw 83: if (rtnext != NULL && strncmp (rtnext, "m", PATHLEN - 1) == 0) {
1.1 snw 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;
1.4 ! snw 100: char rpath[PATHLEN];
1.1 snw 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:
1.4 ! snw 121: snprintf (rpath, PATHLEN - 1, "%s/%s.m", fma_routine_path, opts[fma_base_opt]);
1.1 snw 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;
1.4 ! snw 147: char rpath[PATHLEN];
1.1 snw 148: /* char *editor; */
149:
150: if (optc < fma_min_args) {
151: fprintf (stderr, "fmadm: must supply routine name\n");
152: return 1;
153: }
154:
1.4 ! snw 155: snprintf (rpath, PATHLEN - 1, "%s/%s.m", fma_routine_path, opts[fma_base_opt]);
1.1 snw 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];
1.4 ! snw 182: char backup_filename[PATHLEN];
1.1 snw 183: char dtstamp[STRLEN];
1.4 ! snw 184: char bup_path[PATHLEN];
1.1 snw 185:
186: buf = gmtime (&t);
187:
188: if (optc > 1) {
1.4 ! snw 189: strncpy (bup_path, opts[fma_base_opt], PATHLEN - 1);
1.1 snw 190: }
191: else {
1.4 ! snw 192: strncpy (bup_path, "/tmp", PATHLEN - 1);
1.1 snw 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);
1.4 ! snw 196: snprintf (backup_filename, PATHLEN - 1, "%s/freem-routines-backup-%s-%s.tar", bup_path, fma_namespace, dtstamp);
1.1 snw 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:
1.4 ! snw 269: if (strncmp (fma_namespace, "SYSTEM", PATHLEN - 1) != 0) {
1.1 snw 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;
1.4 ! snw 406: char output_file[PATHLEN];
! 407: char routine_spec[PATHLEN];
! 408: char filename[PATHLEN];
1.1 snw 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) {
1.4 ! snw 423: strncpy (routine_spec, "*", PATHLEN - 1);
1.1 snw 424: }
425:
1.4 ! snw 426: strncpy (output_file, opts[1], PATHLEN - 1);
! 427: strncpy (routine_spec, opts[2], PATHLEN - 1);
1.1 snw 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:
1.4 ! snw 473: strncpy (filename, ent->d_name, PATHLEN - 1);
1.1 snw 474:
475: rtnname = strtok (filename, ".");
476: rtnext = strtok (NULL, ".");
477:
1.4 ! snw 478: if (rtnext != NULL && strncmp (rtnext, "m", PATHLEN - 1) == 0) {
1.1 snw 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;
1.4 ! snw 507: char rtnfile[PATHLEN];
1.1 snw 508: char line[FM_STR_MAX];
509:
1.4 ! snw 510: snprintf (rtnfile, PATHLEN - 1, "%s/%s.m", fma_routine_path, rtn_name);
1.1 snw 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:
1.4 ! snw 542: char rpath[PATHLEN];
1.1 snw 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:
1.4 ! snw 557: snprintf (rpath, PATHLEN - 1, "%s/%s.m", fma_routine_path, opts[i]);
1.1 snw 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>