Annotation of freem/src/fmadm.c, revision 1.33
1.1 snw 1: /*
1.33 ! snw 2: * $Id: fmadm.c,v 1.32 2025/04/09 19:52:02 snw Exp $
1.1 snw 3: * FreeM Administration Tool
4: *
5: *
1.6 snw 6: * Author: Serena Willis <snw@coherent-logic.com>
1.1 snw 7: * Copyright (C) 1998 MUG Deutschland
1.7 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.8 snw 26: * $Log: fmadm.c,v $
1.33 ! snw 27: * Revision 1.32 2025/04/09 19:52:02 snw
! 28: * Eliminate as many warnings as possible while building with -Wall
! 29: *
1.32 snw 30: * Revision 1.31 2025/04/04 19:43:18 snw
31: * Switch to using environment catalog to determine user and group for environment, and remove -u and -g flags from freem
32: *
1.31 snw 33: * Revision 1.30 2025/04/03 20:48:14 snw
34: * Improve daemon error diagnostics and bump to 0.63.0-rc3
35: *
1.30 snw 36: * Revision 1.29 2025/04/03 01:41:02 snw
37: * New features frozen; prepare 0.63.0-rc1
38: *
1.29 snw 39: * Revision 1.28 2025/04/02 19:59:38 snw
40: * Automatically modify env.conf from fmadm reconfigure
41: *
1.28 snw 42: * Revision 1.27 2025/04/02 15:36:25 snw
43: * Do extensive result checking for environment stop/start/restart in fmadm
44: *
1.27 snw 45: * Revision 1.26 2025/04/02 14:37:57 snw
46: * Improve environment control parts of fmadm
47: *
1.26 snw 48: * Revision 1.25 2025/04/02 04:50:49 snw
49: * Allow vendor routines to be upgraded
50: *
1.25 snw 51: * Revision 1.24 2025/04/02 03:02:42 snw
52: * Stop requiring users to pass -e to fmadm when -u or -g are passed
53: *
1.24 snw 54: * Revision 1.23 2025/04/02 02:16:27 snw
55: * Add fmadm status environment command and move journals to a better location
56: *
1.23 snw 57: * Revision 1.22 2025/04/01 23:21:45 snw
58: * fmadm commands for stopping, starting, and restarting environments now functional
59: *
1.22 snw 60: * Revision 1.21 2025/04/01 20:11:46 snw
61: * Further work on fmadm
62: *
1.21 snw 63: * Revision 1.20 2025/04/01 16:37:12 snw
64: * Configure DEFAULT environment the same as others, and set permissions/ownership directly in fmadm configure. Add env.conf file as a centralized configuration listing all environments.
65: *
1.20 snw 66: * Revision 1.19 2025/04/01 14:32:11 snw
67: * Begin work on environment and namespace reorg
68: *
1.19 snw 69: * Revision 1.18 2025/03/31 16:33:56 snw
70: * Work on fmadm edit global
71: *
1.18 snw 72: * Revision 1.17 2025/03/30 01:36:58 snw
73: * Make it easier to bring back fma_gedit, fix double-free in global handler, limit $CHAR to 7-bit ASCII
74: *
1.17 snw 75: * Revision 1.16 2025/03/24 20:59:58 snw
76: * Try using DosCopy API instead of built-in cp function on OS/2
77: *
1.16 snw 78: * Revision 1.15 2025/03/24 20:58:05 snw
79: * Try using DosCopy API instead of built-in cp function on OS/2
80: *
1.15 snw 81: * Revision 1.14 2025/03/24 20:57:06 snw
82: * Try using DosCopy API instead of built-in cp function on OS/2
83: *
1.14 snw 84: * Revision 1.13 2025/03/24 20:15:09 snw
85: * Set file permissions on freemd.exe on OS/2 in fmadm configure
86: *
1.13 snw 87: * Revision 1.12 2025/03/24 20:13:34 snw
88: * Set file permissions on freemd.exe on OS/2 in fmadm configure
89: *
1.12 snw 90: * Revision 1.11 2025/03/24 19:25:48 snw
91: * Make fmadm configure copy freem.exe to freemd.exe for daemon operation on OS/2 systems
92: *
1.11 snw 93: * Revision 1.10 2025/03/24 19:22:16 snw
94: * Make fmadm configure copy freem.exe to freemd.exe for daemon operation on OS/2 systems
95: *
1.10 snw 96: * Revision 1.9 2025/03/24 19:19:42 snw
97: * Make fmadm configure copy freem.exe to freemd.exe for daemon operation on OS/2 systems
98: *
1.9 snw 99: * Revision 1.8 2025/03/22 18:43:54 snw
100: * Make STRLEN 255 chars and add BIGSTR macro for larger buffers
101: *
1.8 snw 102: * Revision 1.7 2025/03/09 19:14:25 snw
103: * First phase of REUSE compliance and header reformat
104: *
1.7 snw 105: *
106: * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
107: * SPDX-License-Identifier: AGPL-3.0-or-later
1.1 snw 108: **/
109:
110: #include <sys/types.h>
111: #include <sys/stat.h>
1.19 snw 112: #include <pwd.h>
113: #include <grp.h>
1.1 snw 114: #include <stddef.h>
115: #include <stdio.h>
116: #include <string.h>
117: #include <dirent.h>
118: #include <stdlib.h>
119: #include <unistd.h>
120: #include <errno.h>
1.4 snw 121: #include <ctype.h>
1.1 snw 122: #include "config.h"
123: #include "transact.h"
124: #include "namespace.h"
125: #include "fs.h"
126:
1.14 snw 127: #if defined(__OS2__)
128: # include <os2.h>
129: #endif
130:
1.1 snw 131: #ifdef HAVE_LIBREADLINE
132: # if defined(HAVE_READLINE_READLINE_H)
133: # include <readline/readline.h>
134: # elif defined(HAVE_READLINE_H)
135: # include <readline.h>
136: # else /* !defined(HAVE_READLINE_H) */
137: extern char *readline ();
138: # endif /* !defined(HAVE_READLINE_H) */
139: /*char *cmdline = NULL;*/
140: #else /* !defined(HAVE_READLINE_READLINE_H) */
141: /* no readline */
142: #endif /* HAVE_LIBREADLINE */
143:
144: #ifdef HAVE_READLINE_HISTORY
145: # if defined(HAVE_READLINE_HISTORY_H)
146: # include <readline/history.h>
147: # elif defined(HAVE_HISTORY_H)
148: # include <history.h>
149: # else /* !defined(HAVE_HISTORY_H) */
150: extern void add_history ();
151: extern int write_history ();
152: extern int read_history ();
153: # endif /* defined(HAVE_READLINE_HISTORY_H) */
154: /* no history */
155: #endif /* HAVE_READLINE_HISTORY */
156:
157:
158: #include "fmadm.h"
159: #include "errmsg.h"
160: #include "iniconf.h"
161: #include "init.h"
162: #include "version.h"
163: #include "shmmgr.h"
164: #include "jobtab.h"
165: #include "locktab.h"
166:
167: /* namespace configuration */
168: char fma_environment[STRLEN];
169: char fma_namespace[STRLEN];
1.8 snw 170: char fma_routine_path[PATHLEN];
171: char fma_global_path[PATHLEN];
172: char fma_journal_path[PATHLEN];
173: char fma_pct_global_path[PATHLEN];
174: char fma_pct_routine_path[PATHLEN];
1.1 snw 175: char fma_journal_cut_threshold[STRLEN];
1.8 snw 176: char fma_locktab[PATHLEN];
1.1 snw 177: short fma_base_opt = 1;
178: short fma_min_args = 2;
179: short fma_explicit_namespace = FALSE;
180: short fma_explicit_environment = FALSE;
181:
182: /* miscellaneous global state */
183: char obj_str[STRLEN];
184:
185: extern char config_file[4096];
1.20 snw 186: extern char env_config_file[4096];
187: extern char env_user[255];
188: extern char env_group[255];
1.29 snw 189: extern char env_enabled[10];
1.1 snw 190:
191: int fm_shell(void);
192: void fm_checkperms(void);
193: void fm_reconfigure(void);
194: void fm_configure(void);
1.21 snw 195: int fm_daemonctl (short action, short object, int optc, char **options);
1.1 snw 196: void fm_write (FILE *file, char *buf);
197: int fma_jobs_remove (int optc, char **opts);
1.20 snw 198: void set_permissions(char *path, char *user, char *grp, int mode);
1.27 snw 199: int fm_environment_running (char *env);
1.21 snw 200: extern int read_profile_string(char *file, char *section, char *key, char *value);
1.1 snw 201:
202: int main (int argc, char **argv)
203: {
204: char action[STRLEN];
205:
206: short act = -1;
207: short obj = -1;
208:
209: char **opts;
210: int optc = argc - 3;
211:
212: int i = 0;
213: int j = 1;
214: int base_arg = 4;
215: int k = 0;
216:
217: short got_action = FALSE;
218: short got_object = FALSE;
219:
1.29 snw 220: strcpy (env_enabled, "true");
1.1 snw 221:
222: /* snprintf (config_file, 4096, "%s/freem.conf", SYSCONFDIR); */
223:
224: base_arg = 1;
225:
226: /* enforce action in argv[1] */
227: if (argc > 1) {
228: if (argv[1][0] == '-') {
229: fprintf (stderr, "fmadm: first argument, if given, must be an action, not a flag\n");
230: fmadm_usage ();
231: exit (1);
232: }
233: }
234:
235: for (i = base_arg; i < argc; i++) {
236: if (i == 1 && isalpha (argv[i][0])) {
237: got_action = TRUE;
238: strncpy (action, argv[i], STRLEN - 1);
239: base_arg++;
240: }
241: if (i == 2 && isalpha (argv[i][0])) {
242: got_object = TRUE;
243: strncpy (obj_str, argv[i], STRLEN - 1);
244: base_arg++;
245: }
246: if (argv[i][0] == '-') {
247:
248: switch (argv[i][1]) {
1.20 snw 249:
250: case 'u':
251: if (argv[i][2] != '=') {
252: fprintf (stderr, "fmadm: missing equals sign in flag -%c\n", argv[i][1]);
253: fmadm_usage ();
254: exit (1);
255: }
256:
257: k = 0;
258:
259: for (j = 3; j < strlen (argv[i]); j++) {
260: env_user[k++] = argv[i][j];
261: }
262:
263: base_arg++;
264:
265: break;
266:
267: case 'g':
268: if (argv[i][2] != '=') {
269: fprintf (stderr, "fmadm: missing equals sign in flag -%c\n", argv[i][1]);
270: fmadm_usage ();
271: exit (1);
272: }
273:
274: k = 0;
275:
276: for (j = 3; j < strlen (argv[i]); j++) {
277: env_group[k++] = argv[i][j];
278: }
279:
280: base_arg++;
281:
282: break;
283:
1.1 snw 284:
285: case 'e':
286: if (argv[i][2] != '=') {
287: fprintf (stderr, "fmadm: missing equals sign in flag -%c\n", argv[i][1]);
288: fmadm_usage ();
289: exit (1);
290: }
291:
292: k = 0;
293:
294: for (j = 3; j < strlen (argv[i]); j++) {
295: fma_environment[k++] = argv[i][j];
296: }
1.21 snw 297:
298: if (strcmp (fma_environment, "all") == 0 ) {
299: fprintf (stderr, "fmadm: 'all' is an invalid environment name\n");
300: exit (1);
301: }
1.1 snw 302:
303: fma_explicit_environment = TRUE;
304: base_arg++;
305:
306: break;
1.29 snw 307:
308: case 'E':
309: if (argv[i][2] != '=') {
310: fprintf (stderr, "fmadm: missing equals sign in flag -%c\n", argv[i][1]);
311: fmadm_usage ();
312: exit (1);
313: }
314:
315: k = 0;
316:
317: for (j = 3; j < strlen (argv[i]); j++) {
318: env_enabled[k++] = argv[i][j];
319: }
320: env_enabled[k] = '\0';
321:
322: if ((strcmp (env_enabled, "true") != 0) && (strcmp (env_enabled, "false") != 0)) {
323: fprintf (stderr, "fmadm: -E (environment enabled) option must be either 'true' or 'false'\n");
324: fmadm_usage ();
325: exit (1);
326: }
327:
328: base_arg++;
329:
330: break;
331:
1.1 snw 332:
333: case 'n':
334: if (argv[i][2] != '=') {
335: fprintf (stderr, "fmadm: missing equals sign in flag -%c\n", argv[i][1]);
336: fmadm_usage ();
337: exit (1);
338: }
339:
340: k = 0;
341:
342: for (j = 3; j < strlen (argv[i]); j++) {
343: fma_namespace[k++] = argv[i][j];
344: }
345:
346: fma_explicit_namespace = TRUE;
347: base_arg++;
348:
349: break;
350:
351: }
352: }
353: }
1.24 snw 354:
1.21 snw 355: if (obj != OBJ_DAEMON) {
356: if (strlen (env_user) == 0) {
357: snprintf (env_user, 6, "freem");
358: }
359:
360: if (strlen (env_group) == 0) {
361: snprintf (env_group, 6, "freem");
362: }
1.20 snw 363:
1.1 snw 364:
1.21 snw 365: if (!fma_explicit_environment) snprintf (fma_environment, 4096, "DEFAULT");
366: if (!fma_explicit_namespace) snprintf (fma_namespace, 4096, "SYSTEM");
367:
368: snprintf (config_file, 4096, "%s/freem/%s/freem.conf", SYSCONFDIR, fma_environment);
369: }
1.1 snw 370:
1.20 snw 371: snprintf (env_config_file, 4096, "%s/freem/env.conf", SYSCONFDIR);
372:
1.26 snw 373: /*
1.1 snw 374: printf ("action = '%s' object = '%s' environment = '%s' namespace = '%s' config_file = '%s' base_arg = '%d' next argument = '%s'\n", action, obj_str, fma_environment, fma_namespace, config_file, base_arg, argv[base_arg]);
375: exit(1);
1.26 snw 376: */
1.1 snw 377:
1.21 snw 378: /* override for fmadm configure and daemon stuff */
1.1 snw 379: if (got_action) {
380: if (strcmp (argv[1], "configure") == 0) {
381: fm_configure ();
382: exit (0);
383: }
384: else if (strcmp (argv[1], "reconfigure") == 0) {
385: fm_reconfigure ();
386: exit (0);
387: }
1.21 snw 388: else if (strcmp (argv[1], "start") == 0 && strcmp (argv[2], "environment") == 0) {
389: act = ACT_START;
390: obj = OBJ_DAEMON;
1.26 snw 391: goto process_args;
1.21 snw 392: }
393: else if (strcmp (argv[1], "stop") == 0 && strcmp (argv[2], "environment") == 0) {
394: act = ACT_STOP;
395: obj = OBJ_DAEMON;
1.26 snw 396: goto process_args;
1.21 snw 397: }
398: else if (strcmp (argv[1], "restart") == 0 && strcmp (argv[2], "environment") == 0) {
399: act = ACT_RESTART;
400: obj = OBJ_DAEMON;
1.26 snw 401: goto process_args;
1.23 snw 402: }
403: else if (strcmp (argv[1], "status") == 0 && strcmp (argv[2], "environment") == 0) {
404: act = ACT_STATUS;
405: obj = OBJ_DAEMON;
1.26 snw 406: goto process_args;
1.21 snw 407: }
1.23 snw 408:
1.1 snw 409: }
410:
411: pid = getpid ();
412:
413: shm_init (16777216);
414: tp_init ();
415: jobtab_init ();
416: job_init (TRUE);
417:
418: fm_sig_init ();
1.21 snw 419:
1.1 snw 420: /* go to fmadm shell if no arguments passed */
421: if (!got_action && !got_object) return fm_shell ();
422:
423: if (argc > 1 && strcmp (argv[1], "checkperms") == 0) {
424: fm_checkperms ();
425: exit (0);
426: }
427:
428: set_namespace (fma_namespace, FALSE);
1.26 snw 429:
430: process_args:
1.1 snw 431: /* allocate opts array */
432:
433: /* first dimension */
434: if ((opts = (char **) malloc (FMA_MAXARGS * sizeof (char *))) == NULL) {
435: fprintf (stderr, "fmadm [FATAL]: could not acquire memory\n");
436: return 1;
437: }
438:
439: /* second dimension */
440: for (i = 0; i < FMA_MAXARGS; i++) {
441: if ((opts[i] = (char *) malloc (STRLEN * sizeof (char *))) == NULL) {
442: fprintf (stderr, "fmadm [FATAL]: could not acquire memory\n");
443: return 1;
444: }
445: }
446:
447: /* copy argv[base_arg] through argv[argc - 1] to opts[1] through opts[argc - 3] */
448:
449: strncpy (opts[0], argv[0], STRLEN - 1); /* preserve argv[0] */
450:
451: j = 1;
452: for (i = base_arg; i < argc; i++) {
1.26 snw 453: if (i > FMA_MAXARGS) return fmadm_usage();
454: /* bail if we're going to overrun the array */
1.1 snw 455: strncpy (opts[j++], argv[i], STRLEN - 1);
456: }
457:
458: if (strncmp (action, "list", STRLEN - 1) == 0) act = ACT_LIST;
459: else if (strncmp (action, "examine", STRLEN - 1) == 0) act = ACT_EXAMINE;
460: else if (strncmp (action, "verify", STRLEN - 1) == 0) act = ACT_VERIFY;
461: else if (strncmp (action, "compact", STRLEN - 1) == 0) act = ACT_COMPACT;
462: else if (strncmp (action, "repair", STRLEN - 1) == 0) act = ACT_REPAIR;
463: else if (strncmp (action, "create", STRLEN - 1) == 0) act = ACT_CREATE;
464: else if (strncmp (action, "remove", STRLEN - 1) == 0) act = ACT_REMOVE;
465: else if (strncmp (action, "import", STRLEN - 1) == 0) act = ACT_IMPORT;
466: else if (strncmp (action, "export", STRLEN - 1) == 0) act = ACT_EXPORT;
467: else if (strncmp (action, "backup", STRLEN - 1) == 0) act = ACT_BACKUP;
468: else if (strncmp (action, "restore", STRLEN - 1) == 0) act = ACT_RESTORE;
469: else if (strncmp (action, "migrate", STRLEN - 1) == 0) act = ACT_MIGRATE;
1.21 snw 470: else if (strncmp (action, "edit", STRLEN - 1) == 0) act = ACT_EDIT;
471: else if (strncmp (action, "start", STRLEN - 1) == 0) act = ACT_START;
472: else if (strncmp (action, "stop", STRLEN - 1) == 0) act = ACT_STOP;
473: else if (strncmp (action, "restart", STRLEN - 1) == 0) act = ACT_RESTART;
1.26 snw 474: else if (strncmp (action, "status", STRLEN - 1) == 0) act = ACT_STATUS;
1.1 snw 475: else return fmadm_usage();
476:
477: if (strncmp (obj_str, "lock", STRLEN - 1) == 0) obj = OBJ_LOCK;
478: else if (strncmp (obj_str, "journal", STRLEN - 1) == 0) obj = OBJ_JOURNAL;
479: else if (strncmp (obj_str, "namespace", STRLEN - 1) == 0) obj = OBJ_NAMESPACE;
480: else if (strncmp (obj_str, "global", STRLEN - 1) == 0) obj = OBJ_GLOBAL;
481: else if (strncmp (obj_str, "routine", STRLEN - 1) == 0) obj = OBJ_ROUTINE;
482: else if (strncmp (obj_str, "job", STRLEN - 1) == 0) obj = OBJ_JOB;
1.21 snw 483: else if (strncmp (obj_str, "environment", STRLEN - 1) == 0) obj = OBJ_DAEMON;
1.1 snw 484: else return fmadm_usage();
485:
1.21 snw 486: if (act > ACT_EDIT) goto act_switch;
487:
1.1 snw 488: if (get_conf (fma_namespace, "routines_path", fma_routine_path) == FALSE) {
489: fprintf (stderr, "fmadm: cannot determine routine path for namespace %s\n", fma_namespace);
490: return 1;
491: }
492:
493: if (get_conf (fma_namespace, "globals_path", fma_global_path) == FALSE) {
494: fprintf (stderr, "fmadm: cannot determine global path for namespace %s\n", fma_namespace);
495: return 1;
496: }
497:
498: if (get_conf ("SYSTEM", "globals_path", fma_pct_global_path) == FALSE) {
499: fprintf (stderr, "fmadm: cannot determine %% global path for namespace %s\n", "SYSTEM");
500: return 1;
501: }
502:
503: if (get_conf ("SYSTEM", "routines_path", fma_pct_routine_path) == FALSE) {
504: fprintf (stderr, "fmadm: cannot determine %% routine path for namespace %s\n", "SYSTEM");
505: return 1;
506: }
507:
508: if (get_conf ("SYSTEM", "journal_file", fma_journal_path) == FALSE) {
509: strcpy (fma_journal_path, "");
510: }
511:
512: if (get_conf ("SYSTEM", "journal_cut_threshold", fma_journal_cut_threshold) == FALSE) {
513: strcpy (fma_journal_cut_threshold, "1073741824");
514: }
515:
516: strcpy (gloplib, fma_pct_global_path);
517: stcnv_c2m (gloplib);
518:
519: strcpy (glopath, fma_global_path);
520: stcnv_c2m (glopath);
521:
522:
1.21 snw 523: act_switch:
1.1 snw 524: switch (act) {
525:
526:
527: case ACT_LIST:
528: fmadm_exit (fm_list (obj, optc, opts));
529:
530:
531: case ACT_EXAMINE:
532: fmadm_exit (fm_examine (obj, optc, opts));
533:
534:
535: case ACT_VERIFY:
536: fmadm_exit (fm_verify (obj, optc, opts));
537:
538:
539: case ACT_COMPACT:
540: fmadm_exit (fm_compact (obj, optc, opts));
541:
542:
543: case ACT_REPAIR:
544: fmadm_exit (fm_repair (obj, optc, opts));
545:
546:
547: case ACT_CREATE:
548: fmadm_exit (fm_create (obj, optc, opts));
549:
550:
551: case ACT_REMOVE:
552: fmadm_exit (fm_remove (obj, optc, opts));
553:
554:
555: case ACT_IMPORT:
556: fmadm_exit (fm_import (obj, optc, opts));
557:
558:
559: case ACT_EXPORT:
560: fmadm_exit (fm_export (obj, optc, opts));
561:
562:
563: case ACT_BACKUP:
564: fmadm_exit (fm_backup (obj, optc, opts));
565:
566:
567: case ACT_RESTORE:
568: fmadm_exit (fm_restore (obj, optc, opts));
569:
570:
571: case ACT_MIGRATE:
572: fmadm_exit (fm_migrate (obj, optc, opts));
573:
574:
575: case ACT_EDIT:
576: fmadm_exit (fm_edit (obj, optc, opts));
577:
1.21 snw 578: case ACT_START:
579: case ACT_STOP:
580: case ACT_RESTART:
1.23 snw 581: case ACT_STATUS:
1.21 snw 582: fmadm_exit (fm_daemonctl (act, obj, optc, opts));
1.1 snw 583:
584: default:
585: return fmadm_usage();
586: }
587:
588: return 0; /* should never be reached */
589:
590: } /* main() */
591:
592: int fm_shell (void)
593: {
594:
595: #if defined(HAVE_LIBREADLINE) && !defined(_AIX)
596: int cmd;
597: int i;
598: int j;
599: int obj;
600: int optc;
601: int argc;
602: char **args;
603: char **opts;
604: char *fmarl_buf;
605: char *fma_prompt = (char *) malloc (STRLEN * sizeof (char));
606: char *cmdt = (char *) malloc (65535 * sizeof (char));
607: char *result = (char *) malloc (65535 * sizeof (char));
608:
1.33 ! snw 609: obj = 0;
1.1 snw 610:
611: snprintf (fma_prompt, STRLEN - 1, "fmadm [%s]> ", fma_namespace);
612:
613: if (get_conf (fma_namespace, "routines_path", fma_routine_path) == FALSE) {
614: fprintf (stderr, "fmadm: cannot determine routine path for namespace %s\n", fma_namespace);
615: return 1;
616: }
617:
618: if (get_conf (fma_namespace, "globals_path", fma_global_path) == FALSE) {
619: fprintf (stderr, "fmadm: cannot determine global path for namespace %s\n", fma_namespace);
620: return 1;
621: }
622:
623: if (get_conf ("SYSTEM", "globals_path", fma_pct_global_path) == FALSE) {
624: fprintf (stderr, "fmadm: cannot determine %% global path for namespace %s\n", "SYSTEM");
625: return 1;
626: }
627:
628: if (get_conf ("SYSTEM", "routines_path", fma_pct_routine_path) == FALSE) {
629: fprintf (stderr, "fmadm: cannot determine %% routine path for namespace %s\n", "SYSTEM");
630: return 1;
631: }
632:
633: if (get_conf ("SYSTEM", "journal_file", fma_journal_path) == FALSE) {
634: strcpy (fma_journal_path, "");
635: }
636:
637: if (get_conf ("SYSTEM", "journal_cut_threshold", fma_journal_cut_threshold) == FALSE) {
638: strcpy (fma_journal_cut_threshold, "1073741824");
639: }
640:
641: strcpy (gloplib, fma_pct_global_path);
642: stcnv_c2m (gloplib);
643:
644: strcpy (glopath, fma_global_path);
645: stcnv_c2m (glopath);
646:
647: /* allocate args array */
648:
649: /* first dimension */
650: if ((args = (char **) malloc (FMA_MAXARGS * sizeof (char *))) == NULL) {
651: fprintf (stderr, "fmadm [FATAL]: could not acquire memory\n");
652: return 1;
653: }
654:
655: /* second dimension */
656: for (i = 0; i < FMA_MAXARGS; i++) {
657: if ((args[i] = (char *) malloc (STRLEN * sizeof (char *))) == NULL) {
658: fprintf (stderr, "fmadm [FATAL]: could not acquire memory\n");
659: return 1;
660: }
661: }
662:
663: /* allocate opts array */
664:
665: /* first dimension */
666: if ((opts = (char **) malloc (FMA_MAXARGS * sizeof (char *))) == NULL) {
667: fprintf (stderr, "fmadm [FATAL]: could not acquire memory\n");
668: return 1;
669: }
670:
671: /* second dimension */
672: for (i = 0; i < FMA_MAXARGS; i++) {
673: if ((opts[i] = (char *) malloc (STRLEN * sizeof (char *))) == NULL) {
674: fprintf (stderr, "fmadm [FATAL]: could not acquire memory\n");
675: return 1;
676: }
677: }
678:
679:
680: for (;;) {
681:
682: fmarl_buf = readline (fma_prompt);
683:
684: if (fmarl_buf == (char *) NULL) continue;
685:
686: cmdt = strtok (fmarl_buf, " ");
687:
1.2 snw 688: if (cmdt == (char *) NULL) continue;
689:
1.1 snw 690: for (i = 0; i < strlen (cmdt); i++) cmdt[i] = cmdt[i] | 0140;
691:
692: if (strcmp (cmdt, "exit") == 0) cmd = FMAC_EXIT;
693: else if (strcmp (cmdt, "quit") == 0) cmd = FMAC_EXIT;
694: else if (strcmp (cmdt, "select") == 0) cmd = FMAC_SELECT;
695: else if (strcmp (cmdt, "list") == 0) cmd = FMAC_LIST;
696: else if (strcmp (cmdt, "examine") == 0) cmd = FMAC_EXAMINE;
697: else if (strcmp (cmdt, "verify") == 0) cmd = FMAC_VERIFY;
698: else if (strcmp (cmdt, "compact") == 0) cmd = FMAC_COMPACT;
699: else if (strcmp (cmdt, "repair") == 0) cmd = FMAC_REPAIR;
700: else if (strcmp (cmdt, "create") == 0) cmd = FMAC_CREATE;
701: else if (strcmp (cmdt, "import") == 0) cmd = FMAC_IMPORT;
702: else if (strcmp (cmdt, "export") == 0) cmd = FMAC_EXPORT;
703: else if (strcmp (cmdt, "backup") == 0) cmd = FMAC_BACKUP;
704: else if (strcmp (cmdt, "restore") == 0) cmd = FMAC_RESTORE;
705: else if (strcmp (cmdt, "migrate") == 0) cmd = FMAC_MIGRATE;
706: else if (strcmp (cmdt, "edit") == 0) cmd = FMAC_EDIT;
707: else if (strcmp (cmdt, "set") == 0) cmd = FMAC_SET;
708: else if (strcmp (cmdt, "show") == 0) cmd = FMAC_SHOW;
709: else if (strcmp (cmdt, "remove") == 0) cmd = FMAC_REMOVE;
710: else cmd = FMAC_INVALID;
711:
712: i = 0;
713: while ((result = strtok (NULL, " ")) != NULL) {
714: strcpy (args[i++], result);
715: }
716:
717: argc = i;
718: j = 0;
719:
720: for (i = 1; i < argc; i++) {
721: strncpy (opts[j++], args[i], STRLEN - 1);
722: }
723:
724: optc = argc - 1;
725:
726: if (i > 0) {
727:
728: strcpy (obj_str, args[0]);
729:
730: if (strncmp (obj_str, "lock", STRLEN - 1) == 0) obj = OBJ_LOCK;
731: else if (strncmp (obj_str, "journal", STRLEN - 1) == 0) obj = OBJ_JOURNAL;
732: else if (strncmp (obj_str, "namespace", STRLEN - 1) == 0) obj = OBJ_NAMESPACE;
733: else if (strncmp (obj_str, "global", STRLEN - 1) == 0) obj = OBJ_GLOBAL;
734: else if (strncmp (obj_str, "routine", STRLEN - 1) == 0) obj = OBJ_ROUTINE;
735: else if (strncmp (obj_str, "job", STRLEN - 1) == 0) obj = OBJ_JOB;
736:
737: }
738:
739: switch (cmd) {
740:
741:
742: case FMAC_SELECT:
743:
744:
745: break;
746:
747:
748: case FMAC_LIST:
749: fm_list (obj, optc, opts);
750: break;
751:
752:
753: case FMAC_EXAMINE:
754: fm_examine (obj, optc, opts);
755: break;
756:
757:
758: case FMAC_VERIFY:
759: fm_verify (obj, optc, opts);
760: break;
761:
762:
763: case FMAC_COMPACT:
764: fm_compact (obj, optc, opts);
765: break;
766:
767:
768: case FMAC_REPAIR:
769: fm_repair (obj, optc, opts);
770: break;
771:
772:
773: case FMAC_CREATE:
774: fm_create (obj, optc, opts);
775: break;
776:
777:
778: case FMAC_REMOVE:
779: fm_remove (obj, optc, opts);
780: break;
781:
782:
783: case FMAC_IMPORT:
784: fm_import (obj, optc, opts);
785: break;
786:
787:
788: case FMAC_EXPORT:
789: fm_export (obj, optc, opts);
790: break;
791:
792:
793: case FMAC_BACKUP:
794: fm_backup (obj, optc, opts);
795: break;
796:
797:
798: case FMAC_RESTORE:
799: fm_restore (obj, optc, opts);
800: break;
801:
802:
803: case FMAC_MIGRATE:
804: fm_migrate (obj, optc, opts);
805: break;
806:
807:
808: case FMAC_EDIT:
809: fm_edit (obj, optc, opts);
810: break;
811:
812:
813: case FMAC_SET:
814:
815: if (i < 2) {
816: printf ("fmadm: syntax error\n");
817: break;
818: }
819:
820: if (strcmp (args[0], "namespace") == 0) {
821: strcpy (fma_namespace, args[1]);
822:
823: if (get_conf (fma_namespace, "routines_path", fma_routine_path) == FALSE) {
824: fprintf (stderr, "fmadm: cannot determine routine path for namespace %s\n", fma_namespace);
825: return 1;
826: }
827:
828: if (get_conf (fma_namespace, "globals_path", fma_global_path) == FALSE) {
829: fprintf (stderr, "fmadm: cannot determine global path for namespace %s\n", fma_namespace);
830: return 1;
831: }
832:
833: if (get_conf ("SYSTEM", "globals_path", fma_pct_global_path) == FALSE) {
834: fprintf (stderr, "fmadm: cannot determine %% global path for namespace %s\n", "SYSTEM");
835: return 1;
836: }
837:
838: if (get_conf ("SYSTEM", "routines_path", fma_pct_routine_path) == FALSE) {
839: fprintf (stderr, "fmadm: cannot determine %% routine path for namespace %s\n", "SYSTEM");
840: return 1;
841: }
842:
843: if (get_conf ("SYSTEM", "journal_file", fma_journal_path) == FALSE) {
844: strcpy (fma_journal_path, "");
845: }
846:
847: if (get_conf ("SYSTEM", "journal_cut_threshold", fma_journal_cut_threshold) == FALSE) {
848: strcpy (fma_journal_cut_threshold, "1073741824");
849: }
850:
851: strcpy (gloplib, fma_pct_global_path);
852: stcnv_c2m (gloplib);
853:
854: strcpy (glopath, fma_global_path);
855: stcnv_c2m (glopath);
856:
857: snprintf (fma_prompt, STRLEN - 1, "fmadm [%s]> ", fma_namespace);
858:
859: }
860: else if (strcmp (args[0], "maintenance") == 0) {
861: if (strcmp (args[1], "on") == 0) {
862: shm_config->hdr->maintenance_mode = 1;
863: break;
864: }
865: else if (strcmp (args[1], "off") == 0) {
866: shm_config->hdr->maintenance_mode = 0;
867: break;
868: }
869: else {
870: printf ("fmadm: syntax error\n");
871: }
872:
873: printf ("fmadm: syntax error\n");
874:
875: }
876: else {
877: printf ("fmadm: syntax error\n");
878: break;
879: }
880:
881: break;
882:
883:
884: case FMAC_SHOW:
885: printf ("Namespace: %s\n", fma_namespace);
886: printf ("Routine Path: %s\n", fma_routine_path);
887: printf ("%%-Routine Path: %s\n", fma_pct_routine_path);
888: printf ("Global Path: %s\n", fma_global_path);
889: printf ("%%-Global Path: %s\n", fma_pct_global_path);
890: printf ("Journal File: %s\n", fma_journal_path);
1.5 snw 891: printf ("Journal Cut Threshold: %s bytes\n", fma_journal_cut_threshold);
1.1 snw 892: break;
893:
894: case FMAC_EXIT:
895: fmadm_exit (0);
896: break;
897:
898:
899: default:
900: printf ("fmadm: '%s' is not a valid fmadm command\n", cmdt);
901: break;
902:
903: }
904: }
905:
906: #endif
907:
908: }
909:
910: void fmadm_exit (int retval)
911: {
912: locktab_unlock_all ();
913: job_remove (pid);
914:
915: shm_exit ();
916:
917: exit (retval);
918: }
919:
920: int fmadm_usage (void)
921: {
922:
1.29 snw 923: fprintf (stdout, "\nusage: fmadm <action> <object> [-e=<environment] [-n=<namespace>] [-u=<user>] [-g=<group>] [-E=true|false] [OPTIONS]\n");
1.1 snw 924: fprintf (stdout, " fmadm configure\n");
925: fprintf (stdout, " fmadm reconfigure\n");
926:
927: fprintf (stdout, " <action> can be one of:\n");
928: fprintf (stdout, " list, examine, verify, compact, repair, create, remove,\n");
1.21 snw 929: fprintf (stdout, " import, export, backup, restore, migrate, edit, start,\n");
1.29 snw 930: fprintf (stdout, " stop, restart, status\n\n");
1.1 snw 931:
932: fprintf (stdout, " <object> can be one of:\n");
1.24 snw 933: fprintf (stdout, " lock, journal, namespace, global, routine, job,\n");
1.21 snw 934: fprintf (stdout, " environment\n\n");
1.1 snw 935:
936: fprintf (stdout, " Not all actions are valid for all objects. Please see the FreeM manual\n");
937: fprintf (stdout, " for details on fmadm usage and options.\n\n");
938:
939: return 1;
940:
941: } /* fmadm_usage() */
942:
943: int fm_list (short object, int optc, char **options)
944: {
945:
946: switch (object) {
947:
948: case OBJ_LOCK:
949: return fma_locks_list (optc, options);
950:
951: case OBJ_ROUTINE:
952: return fma_routines_list (optc, options);
953:
954: case OBJ_GLOBAL:
955: return fma_globals_list (optc, options);
956:
957: case OBJ_JOB:
958: return fma_jobs_list (optc, options);
959:
960: default:
961: fprintf (stderr, "fmadm: 'list' is an invalid action for '%s'\n", obj_str);
962: return 1;
963:
964: }
965:
966:
967: } /* fm_list() */
968:
969: int fm_examine (short object, int optc, char **options)
970: {
971:
972: switch (object) {
973:
974: case OBJ_ROUTINE:
975: return fma_routines_examine (optc, options);
976:
977: case OBJ_GLOBAL:
978: return fma_globals_examine (optc, options);
979:
980: case OBJ_JOB:
981: return fma_jobs_examine (optc, options);
982:
983: case OBJ_JOURNAL:
984: return fma_journals_examine (optc, options);
985:
986: default:
987: fprintf (stderr, "fmadm: 'examine' is an invalid action for '%s'\n", obj_str);
988: return 1;
989:
990: }
991:
992: } /* fm_examine() */
993:
994: int fm_verify (short object, int optc, char **options)
995: {
996:
997: switch (object) {
998:
999: case OBJ_GLOBAL:
1000: return fma_globals_verify (optc, options);
1001:
1002: default:
1003: fprintf (stderr, "fmadm: 'examine' is an invalid action for '%s'\n", obj_str);
1004: return 1;
1005:
1006: }
1007:
1008: } /* fm_verify() */
1009:
1010: int fm_compact (short object, int optc, char **options)
1011: {
1012:
1013: switch (object) {
1014:
1015: default:
1016: fprintf (stderr, "fmadm: 'compact' is an invalid action for '%s'\n", obj_str);
1017: return 1;
1018:
1019: }
1020:
1021: } /* fm_compact() */
1022:
1023: int fm_repair (short object, int optc, char **options)
1024: {
1025:
1026: switch (object) {
1027:
1028: default:
1029: fprintf (stderr, "fmadm: 'repair' is an invalid action for '%s'\n", obj_str);
1030: return 1;
1031:
1032: }
1033:
1034: } /* fm_repair() */
1035:
1036: int fm_create (short object, int optc, char **options)
1037: {
1038:
1039: switch (object) {
1040:
1041: default:
1042: fprintf (stderr, "fmadm: 'create' is an invalid action for '%s'\n", obj_str);
1043: return 1;
1044:
1045: }
1046: } /* fm_create() */
1047:
1048: int fm_remove (short object, int optc, char **options)
1049: {
1050:
1051: switch (object) {
1052:
1053: case OBJ_JOB:
1054: return fma_jobs_remove (optc, options);
1055:
1056: case OBJ_LOCK:
1057: return fma_locks_remove (optc, options);
1058:
1059: case OBJ_ROUTINE:
1060: return fma_routines_remove (optc, options);
1061:
1062: case OBJ_GLOBAL:
1063: return fma_globals_remove (optc, options);
1064:
1065: default:
1066: fprintf (stderr, "fmadm: 'remove' is an invalid action for '%s'\n", obj_str);
1067: return 1;
1068:
1069: }
1070:
1071: } /* fm_remove() */
1072:
1073: int fm_import (short object, int optc, char **options)
1074: {
1075:
1076: switch (object) {
1077:
1078: case OBJ_ROUTINE:
1079: return fma_routines_import (optc, options);
1080:
1081: default:
1082: fprintf (stderr, "fmadm: 'import' is an invalid action for '%s'\n", obj_str);
1083: return 1;
1084:
1085: }
1086:
1087: } /* fm_import() */
1088:
1089: int fm_export (short object, int optc, char **options)
1090: {
1091:
1092: switch (object) {
1093:
1094: case OBJ_ROUTINE:
1095: return fma_routines_export (optc, options);
1096:
1097: default:
1098: fprintf (stderr, "fmadm: 'export' is an invalid action for '%s'\n", obj_str);
1099: return 1;
1100:
1101: }
1102:
1103: } /* fm_export() */
1104:
1105: int fm_backup (short object, int optc, char **options)
1106: {
1107:
1108: switch (object) {
1109:
1110: case OBJ_ROUTINE:
1111: return fma_routines_backup (optc, options);
1112:
1113: default:
1114: fprintf (stderr, "fmadm: 'backup' is an invalid action for '%s'\n", obj_str);
1115: return 1;
1116:
1117: }
1118:
1119: } /* fm_backup() */
1120:
1121: int fm_restore (short object, int optc, char **options)
1122: {
1123:
1124: switch (object) {
1125:
1126: case OBJ_JOURNAL:
1127: return fma_journals_restore (optc, options);
1128:
1129: default:
1130: fprintf (stderr, "fmadm: 'restore' is an invalid action for '%s'\n", obj_str);
1131: return 1;
1132:
1133: }
1134:
1135: } /* fm_restore() */
1136:
1137: int fm_migrate (short object, int optc, char **options)
1138: {
1139:
1140: switch (object) {
1141:
1142: default:
1143: fprintf (stderr, "fmadm: 'migrate' is an invalid action for '%s'\n", obj_str);
1144: return 1;
1145:
1146: }
1147:
1148: } /* fm_migrate() */
1149:
1150: int fm_edit (short object, int optc, char **options)
1151: {
1152:
1153: switch (object) {
1154:
1155: case OBJ_ROUTINE:
1156: return fma_routines_edit (optc, options);
1157:
1.18 snw 1158: case OBJ_GLOBAL:
1.1 snw 1159: return fma_globals_edit (optc, options);
1.18 snw 1160:
1.1 snw 1161: default:
1162: fprintf (stderr, "fmadm: 'edit' is an invalid action for '%s'\n", obj_str);
1163: return 1;
1164:
1165: }
1166:
1167: } /* fm_edit() */
1168:
1.22 snw 1169: long fm_get_pid (char *env)
1170: {
1171: char pid_file[4096];
1172: char tmp_pid[255];
1173: FILE *fp;
1174:
1175: snprintf (pid_file, 4095, "%s/freem/run/%s.pid", LOCALSTATEDIR, env);
1176:
1177: if ((fp = fopen (pid_file, "r")) != NULL) {
1178: if (fgets (tmp_pid, 255, fp)) {
1179: fclose (fp);
1180: return atol (tmp_pid);
1181: }
1182: else {
1183: fclose (fp);
1184: return -1;
1185: }
1186: }
1187: else {
1188: return -1;
1189: }
1190: }
1191:
1.26 snw 1192: int fm_validate_environment (char *env)
1193: {
1194: FILE *fp;
1195: char line[255];
1196: char chkline[255];
1197:
1198: snprintf (chkline, 254, "[%s]\n", env);
1199:
1200: if ((fp = fopen (env_config_file, "r")) == NULL) {
1201: fprintf (stderr, "fmadm: could not open %s [%s]\n", env_config_file, strerror (errno));
1202: return FALSE;
1203: }
1204:
1205: while (fgets (line, 254, fp)) {
1206: if (strncmp (line, chkline, 254) == 0) {
1207: fclose (fp);
1208: return TRUE;
1209: }
1210: }
1211:
1212: fclose (fp);
1213: return FALSE;
1214: }
1215:
1.31 snw 1216: int fm_start_environment (char *env)
1.26 snw 1217: {
1218: char basecmd[255];
1219: char cmd[4096];
1.27 snw 1220:
1221: if (fm_environment_running (env) == TRUE) {
1222: return TRUE;
1223: }
1.26 snw 1224:
1225: #if !defined(__OS2__)
1226: snprintf (basecmd, 254, "%s/bin/freem", PREFIX);
1227: #else
1228: snprintf (basecmd, 254, "%s/bin/freemd.exe", PREFIX);
1229: #endif
1230:
1231: #if !defined(__OS2__)
1.31 snw 1232: snprintf (cmd, 4095, "%s -d -e %s", basecmd, env);
1.26 snw 1233: #else
1.31 snw 1234: sprintf (cmd, 4095, "%s -d -k -e %s", basecmd, env);
1.26 snw 1235: #endif
1.27 snw 1236:
1237: system (cmd);
1238:
1239: sleep (1);
1.26 snw 1240:
1.27 snw 1241: return (fm_environment_running (env));
1.26 snw 1242: }
1243:
1244: int fm_stop_environment (char *env)
1245: {
1246: long epid;
1247:
1.27 snw 1248: epid = fm_get_pid (env);
1.26 snw 1249: if (epid > -1) {
1250: kill (epid, SIGINT);
1.27 snw 1251: sleep (5);
1252:
1253: if (fm_environment_running (env) == FALSE) {
1254: return TRUE;
1255: }
1256: else {
1257: kill (epid, SIGTERM);
1258: sleep (5);
1259: if (fm_environment_running (env) == FALSE) {
1260: return TRUE;
1261: }
1262: else {
1263: kill (epid, SIGKILL);
1264: sleep (5);
1265: if (fm_environment_running (env) == FALSE) {
1266: return TRUE;
1267: }
1268: else {
1269: return FALSE;
1270: }
1271: }
1272: }
1.26 snw 1273: }
1274: else {
1.27 snw 1275: return FALSE;
1.26 snw 1276: }
1277: }
1278:
1.27 snw 1279: int fm_environment_running (char *env)
1280: {
1281: long epid;
1282: int result;
1283:
1284: epid = fm_get_pid (env);
1285:
1286: if (epid == -1) {
1287: return FALSE;
1288: }
1289: else {
1290: result = kill (epid, 0);
1291:
1292: return ((result == 0) ? TRUE : FALSE);
1293: }
1294: }
1295:
1.21 snw 1296: int fm_daemonctl (short action, short object, int optc, char **options)
1297: {
1298: FILE *ef;
1299: char *envlist;
1300: char env[255];
1301: char line[255];
1302: char tmps[255];
1303: char *cur_env;
1.23 snw 1304: char verb[40];
1.21 snw 1305: char e_user[255];
1306: char e_grp[255];
1307: char e_ena[10];
1308: char *savptr;
1309: int result;
1.22 snw 1310: long epid;
1.30 snw 1311: int retval;
1.26 snw 1312:
1.30 snw 1313: retval = 0;
1.21 snw 1314:
1315: switch (action) {
1316: case ACT_START:
1317: sprintf (verb, "starting");
1318: break;
1319: case ACT_STOP:
1320: sprintf (verb, "stopping");
1321: break;
1322: case ACT_RESTART:
1323: sprintf (verb, "restarting");
1324: break;
1.23 snw 1325: case ACT_STATUS:
1326: sprintf (verb, "checking status of");
1327: break;
1.21 snw 1328: }
1329:
1330: if (optc) {
1331: /* environment list specified as command-line argument */
1.23 snw 1332: envlist = (char *) malloc (sizeof (char) * BIGSTR);
1333: NULLPTRCHK(envlist,"fm_daemonctl");
1334:
1.26 snw 1335: strcpy (envlist, options[1]);
1.21 snw 1336: }
1337: else {
1338: /* no environment specified; do 'action' for all environments */
1339: envlist = (char *) malloc (sizeof (char) * BIGSTR);
1340: NULLPTRCHK(envlist,"fm_daemonctl");
1341:
1342: ef = fopen (env_config_file, "r");
1343:
1344: while (fgets (line, 254, ef)) {
1345: if (line[0] == '[') {
1346: strncpy (env, &(line[1]), 255);
1347: env[strlen (env) - 2] = '\0';
1348: snprintf (tmps, 255, "%s,", env);
1349: strncat (envlist, tmps, BIGSTR - 1);
1350: }
1351: }
1352: envlist[strlen (envlist) - 1] = '\0';
1353:
1354: fclose (ef);
1355: }
1356:
1357: savptr = envlist;
1358: cur_env = strtok_r (envlist, ",", &savptr);
1359: do {
1.26 snw 1360:
1361: if (fm_validate_environment (cur_env) == FALSE) {
1362: fprintf (stderr, "fmadm: %s is not a valid environment\n", cur_env);
1363: continue;
1364: }
1365:
1.21 snw 1366: result = read_profile_string (env_config_file, cur_env, "enabled", e_ena);
1367: if (result == FALSE || strcmp (e_ena, "true") == 0) {
1368:
1369: result = read_profile_string (env_config_file, cur_env, "user", e_user);
1370: if (result == FALSE) {
1371: strcpy (e_user, "freem");
1372: }
1373: result = read_profile_string (env_config_file, cur_env, "group", e_grp);
1374: if (result == FALSE) {
1375: strcpy (e_grp, "freem");
1376: }
1.22 snw 1377:
1.27 snw 1378: switch (action) {
1379: case ACT_START:
1380: case ACT_STOP:
1381: case ACT_RESTART:
1382: fprintf (stderr, "fmadm: %s environment %s... ", verb, cur_env);
1383: break;
1384: case ACT_STATUS:
1385: fprintf (stderr, "fmadm: %s environment %s\n", verb, cur_env);
1386: break;
1387: }
1.21 snw 1388:
1389: switch (action) {
1.26 snw 1390:
1.21 snw 1391: case ACT_START:
1.31 snw 1392: result = fm_start_environment (cur_env);
1.27 snw 1393: if (result == TRUE) {
1394: fprintf (stderr, "[OK]\n");
1395: }
1396: else {
1397: fprintf (stderr, "[FAIL]\n");
1398: }
1.21 snw 1399: break;
1.26 snw 1400:
1.21 snw 1401: case ACT_STOP:
1.26 snw 1402: result = fm_stop_environment (cur_env);
1.27 snw 1403: if (result == TRUE) {
1404: fprintf (stderr, "[OK]\n");
1405: }
1406: else {
1407: fprintf (stderr, "[FAIL]\n");
1.30 snw 1408: retval++;
1.27 snw 1409: }
1.22 snw 1410: break;
1.26 snw 1411:
1.21 snw 1412: case ACT_RESTART:
1.27 snw 1413: if (fm_stop_environment (cur_env) == TRUE) {
1.31 snw 1414: result = fm_start_environment (cur_env);
1.27 snw 1415: if (result == TRUE) {
1416: fprintf (stderr, "[OK]\n");
1417: }
1418: else {
1419: fprintf (stderr, "[FAIL]\n");
1.30 snw 1420: retval++;
1.27 snw 1421: }
1422: }
1423: else {
1424: fprintf (stderr, "[FAIL]\n");
1.30 snw 1425: retval++;
1.27 snw 1426: }
1.22 snw 1427:
1.21 snw 1428: break;
1.26 snw 1429:
1.23 snw 1430: case ACT_STATUS:
1431: epid = fm_get_pid (cur_env);
1432: if (epid > -1) {
1.32 snw 1433: fprintf (stderr, " - %s environment daemon running as pid %ld\n", cur_env, epid);
1.23 snw 1434: }
1435: else {
1436: fprintf (stderr, " - %s environment daemon does not appear to be running\n", cur_env);
1437: }
1.22 snw 1438: }
1.21 snw 1439: }
1440: else {
1441: printf ("fmadm: %s environment is disabled; skipping\n", cur_env);
1442: }
1443: } while ((cur_env = strtok_r (NULL, ",", &savptr)) != NULL);
1444:
1445: free (envlist);
1.30 snw 1446: exit (retval);
1.21 snw 1447:
1448: } /* fm_daemonctl() */
1449:
1.1 snw 1450: void fm_checkperms(void)
1451: {
1452:
1453: } /* fm_checkperms() */
1454:
1455:
1456: void fm_reconfigure(void)
1457: {
1458: char config_backup[4096];
1459:
1460: int retval;
1461:
1462: if (geteuid () != 0) {
1463: fprintf (stderr, "fmadm: not superuser\n");
1464: exit (1);
1465: }
1466:
1467: snprintf (config_backup, 4095, "%s.orig", config_file);
1468:
1469: fprintf (stderr, "fmadm: reconfiguring FreeM with system defaults for %s...\n", FREEM_VERSION_CSTR);
1470: fprintf (stderr, "fmadm: backing up %s to %s...\t", config_file, config_backup);
1471:
1.29 snw 1472: #if !defined(__OS2__)
1473: retval = cp (config_backup, config_file);
1474: #else
1475: retval = DosCopy (config_file, config_backup);
1476: #endif
1.1 snw 1477:
1478: if (retval == 0) {
1.18 snw 1479: fprintf (stderr, "[OK]\n");
1.1 snw 1480:
1481: fm_configure ();
1482:
1483: fprintf (stderr, "\n\nYou may wish to edit %s if site-specific changes were made to the original FreeM configuration.\n", config_file);
1484: exit (0);
1485: }
1486: else {
1487: fprintf (stderr, "[FAIL (%s)]\n", strerror (errno));
1488: exit (1);
1489: }
1490:
1491: } /* fm_reconfigure() */
1492:
1.29 snw 1493: void update_conf (char *file, char *section, char *key, char *new_value)
1494: {
1495: char old_value[255];
1496: char tbuf[255];
1497:
1498: snprintf (tbuf, 254, "%s.%s", section, key);
1499:
1500: read_profile_string (file, section, key, old_value);
1501: if (strcmp (old_value, new_value) != 0) {
1502: modify_profile_string (file, section, key, new_value);
1503: fprintf (stderr, "\t%-40s%-20s -> %s\n", tbuf, old_value, new_value);
1504: }
1505: else {
1506: fprintf (stderr, "\t%-40s%-20s\n", tbuf, "no change");
1507: }
1508: }
1.1 snw 1509:
1510: void fm_configure (void)
1511: {
1.21 snw 1512: char rundir[4096];
1.19 snw 1513: char varbase[4096];
1.1 snw 1514: char sysrtn[4096];
1515: char sysgbl[4096];
1516: char usrrtn[4096];
1517: char usrgbl[4096];
1518:
1.23 snw 1519: char jnldir[4096];
1.1 snw 1520: char jnlfile[4096];
1521: char jnlmode[4];
1522: char jnlhostid[4096];
1523: char jnlcut[4096];
1524: char hostid[4096];
1525:
1526: char confbase[4096];
1527: char envbase[4096];
1528:
1529: char nsbase[4096];
1530:
1531: char buf[4096];
1532: FILE *fp;
1533:
1.29 snw 1534: int reconfigure = FALSE;
1535:
1.1 snw 1536: struct stat etcstat;
1.19 snw 1537:
1538: DIR *dir;
1539: struct dirent *ent;
1540: char src_dir[4096];
1541: char dest_dir[4096];
1542:
1.20 snw 1543: char *username = env_user;
1544: char *groupname = env_group;
1.28 snw 1545:
1.20 snw 1546: #if !defined(__OS2__)
1.32 snw 1547: struct group *d_grp;
1548: struct passwd *d_user;
1549:
1.24 snw 1550: if (geteuid () != 0) {
1551: fprintf (stderr, "fmadm: not superuser\n");
1552: exit (1);
1553: }
1554:
1.20 snw 1555: if ((d_grp = getgrnam (groupname)) == NULL) {
1556: fprintf (stderr, "fmadm: '%s' group must exist before configuring\n", groupname);
1557: exit (1);
1558: }
1559: if ((d_user = getpwnam (username)) == NULL) {
1560: fprintf (stderr, "fmadm: '%s' user must exist before configuring\n", username);
1561: exit (1);
1562: }
1563: #endif
1.23 snw 1564:
1.19 snw 1565: snprintf (varbase, 4095, "%s/freem", LOCALSTATEDIR);
1.21 snw 1566: snprintf (rundir, 4095, "%s/freem/run", LOCALSTATEDIR);
1.1 snw 1567: snprintf (sysrtn, 4095, "%s/freem/%s/SYSTEM/routines", LOCALSTATEDIR, fma_environment);
1568: snprintf (sysgbl, 4095, "%s/freem/%s/SYSTEM/globals", LOCALSTATEDIR, fma_environment);
1569: snprintf (usrrtn, 4095, "%s/freem/%s/USER/routines", LOCALSTATEDIR, fma_environment);
1570: snprintf (usrgbl, 4095, "%s/freem/%s/USER/globals", LOCALSTATEDIR, fma_environment);
1.23 snw 1571: snprintf (jnldir, 4095, "%s/freem/%s/journals", LOCALSTATEDIR, fma_environment);
1572: snprintf (jnlfile, 4095, "%s/freem_journal_%s.dat", jnldir, fma_environment);
1.1 snw 1573: snprintf (jnlmode, 3, "on");
1574: snprintf (jnlhostid, 4095, "DEFAULT");
1575: snprintf (jnlcut, 4095, "4294967000");
1576:
1577: if (geteuid () != 0) {
1578: fprintf (stderr, "fmadm: not superuser\n");
1579: exit (1);
1580: }
1581:
1582: if (file_exists (config_file)) {
1.29 snw 1583: reconfigure = TRUE;
1.1 snw 1584: }
1.29 snw 1585:
1.1 snw 1586: gethostname (hostid, 4095);
1587: uuid_v4 (buf);
1588:
1589: snprintf (jnlhostid, 4095, "%s:%s", hostid, buf);
1590: snprintf (confbase, 4095, "%s/freem", SYSCONFDIR);
1591: snprintf (envbase, 4095, "%s/freem/%s", SYSCONFDIR, fma_environment);
1592: snprintf (nsbase, 4095, "%s/freem/%s", LOCALSTATEDIR, fma_environment);
1593:
1.9 snw 1594: #if defined(__OS2__)
1595: {
1596: char srcfile[PATHLEN];
1.11 snw 1597: char dstfile[PATHLEN];
1598:
1.9 snw 1599: snprintf (srcfile, PATHLEN, "%s/bin/freem.exe", PREFIX);
1600: snprintf (dstfile, PATHLEN, "%s/bin/freemd.exe", PREFIX);
1.11 snw 1601:
1602: unlink (dstfile);
1.9 snw 1603:
1.10 snw 1604: fprintf (stderr, "fmadm: running on OS/2; will copy %s to %s\n", srcfile, dstfile);
1.12 snw 1605:
1.16 snw 1606: if (DosCopy (srcfile, dstfile, 1) != 0) {
1.9 snw 1607: fprintf (stderr, "fmadm: fatal error copying %s to %s\n", srcfile, dstfile);
1608: exit (1);
1609: }
1.13 snw 1610:
1611: chmod (dstfile, 0755);
1.9 snw 1612: }
1613: #endif
1.1 snw 1614:
1.29 snw 1615: if (reconfigure == FALSE) {
1616: printf ("\nFreeM Initial Environment Configuration\n");
1617: printf ("---------------------------------------\n\n");
1618:
1619: printf ("This utility will create the initial configuration files for ");
1620: printf ("FreeM environment '%s' (owned by %s:%s) in '%s'.\n\n", fma_environment, username, groupname, config_file);
1621: }
1622: else {
1623: printf ("\nFreeM Environment Upgrade/Reconfiguration\n");
1624: printf ("-----------------------------------------\n\n");
1625:
1626: printf ("This utility will update the configuration files for ");
1627: printf ("FreeM environment '%s' (owned by %s:%s) in '%s'.\n\n", fma_environment, username, groupname, config_file);
1628: }
1.9 snw 1629:
1.1 snw 1630: /* check for existence of needed directories */
1631: if (stat (SYSCONFDIR, &etcstat) == -1) {
1.23 snw 1632: fprintf (stderr, "fmadm: creating %s [SYSCONFDIR]\n", SYSCONFDIR);
1.19 snw 1633: mkdir (SYSCONFDIR, 0775);
1.20 snw 1634: set_permissions (SYSCONFDIR, username, groupname, 0775);
1.1 snw 1635: }
1636:
1637: if (stat (confbase, &etcstat) == -1) {
1.23 snw 1638: fprintf (stderr, "fmadm: creating %s [confbase]\n", confbase);
1.19 snw 1639: mkdir (confbase, 0775);
1.20 snw 1640: set_permissions (confbase, username, groupname, 0775);
1.1 snw 1641: }
1642:
1.19 snw 1643: if (stat (varbase, &etcstat) == -1) {
1.23 snw 1644: fprintf (stderr, "fmadm: creating %s [varbase]\n", varbase);
1.19 snw 1645: mkdir (varbase, 0775);
1.20 snw 1646: set_permissions (varbase, username, groupname, 0775);
1.19 snw 1647: }
1.21 snw 1648:
1.23 snw 1649: if (stat (envbase, &etcstat) == -1) {
1650: fprintf (stderr, "fmadm: creating %s [envbase]\n", envbase);
1651: mkdir (envbase, 0775);
1652: set_permissions (envbase, username, groupname, 0775);
1653: }
1654:
1.21 snw 1655: if (stat (rundir, &etcstat) == -1) {
1.23 snw 1656: fprintf (stderr, "fmadm: creating %s [rundir]\n", rundir);
1.21 snw 1657: mkdir (rundir, 0777);
1658: chmod (rundir, 0777);
1659: }
1660:
1.1 snw 1661: if (stat (nsbase, &etcstat) == -1) {
1.23 snw 1662: fprintf (stderr, "fmadm: creating %s [nsbase]\n", nsbase);
1.19 snw 1663: mkdir (nsbase, 0775);
1.20 snw 1664: set_permissions (nsbase, username, groupname, 0775);
1.1 snw 1665: }
1666:
1.23 snw 1667: if (stat (jnldir, &etcstat) == -1) {
1668: fprintf (stderr, "fmadm: creating %s [jnldir]\n", jnldir);
1669: mkdir (jnldir, 0775);
1670: set_permissions (jnldir, username, groupname, 0775);
1671: }
1672:
1673:
1.19 snw 1674: snprintf (src_dir, 4095, "%s/freem/mlib", DATADIR);
1675: snprintf (dest_dir, 4095, "%s/freem/%s/SYSTEM/routines", LOCALSTATEDIR, fma_environment);
1.29 snw 1676:
1677: if (reconfigure == FALSE) {
1678: fprintf (stderr, "fmadm: populating new environment '%s'\n", fma_environment);
1679: }
1680: else {
1681: fprintf (stderr, "fmadm: upgrading environment '%s'\n", fma_environment);
1682: }
1.19 snw 1683:
1684: snprintf (buf, 4095, "%s/freem/%s/SYSTEM", LOCALSTATEDIR, fma_environment);
1685: mkdir (buf, 0775);
1.20 snw 1686: set_permissions (buf, username, groupname, 0775);
1.19 snw 1687:
1688: snprintf (buf, 4095, "%s/freem/%s/USER", LOCALSTATEDIR, fma_environment);
1689: mkdir (buf, 0775);
1.20 snw 1690: set_permissions (buf, username, groupname, 0775);
1.19 snw 1691:
1692: snprintf (buf, 4095, "%s/freem/%s/SYSTEM/routines", LOCALSTATEDIR, fma_environment);
1693: mkdir (buf, 0775);
1.20 snw 1694: set_permissions (buf, username, groupname, 0775);
1.19 snw 1695:
1696: snprintf (buf, 4095, "%s/freem/%s/USER/globals", LOCALSTATEDIR, fma_environment);
1697: mkdir (buf, 0775);
1.20 snw 1698: set_permissions (buf, username, groupname, 0775);
1.19 snw 1699:
1700: snprintf (buf, 4095, "%s/freem/%s/SYSTEM/globals", LOCALSTATEDIR, fma_environment);
1701: mkdir (buf, 0775);
1.20 snw 1702: set_permissions (buf, username, groupname, 0775);
1.19 snw 1703:
1704: snprintf (buf, 4095, "%s/freem/%s/USER/routines", LOCALSTATEDIR, fma_environment);
1705: mkdir (buf, 0775);
1.20 snw 1706: set_permissions (buf, username, groupname, 0775);
1.19 snw 1707:
1.25 snw 1708: fprintf (stderr, "fmadm: copying vendor routines from '%s' to '%s'...\n", src_dir, dest_dir);
1.1 snw 1709:
1.19 snw 1710: if ((dir = opendir (src_dir)) == NULL) {
1711: fprintf (stderr, "\nfmadm: could not open source directory %s\n", src_dir);
1712: exit (1);
1713: }
1714:
1715: while ((ent = readdir (dir)) != NULL) {
1716: char infile[4096];
1717: char outfile[4096];
1.1 snw 1718:
1.25 snw 1719: if ((strcmp (ent->d_name, ".") != 0) && (strcmp (ent->d_name, "..") != 0)) {
1.19 snw 1720:
1721: snprintf (infile, 4095, "%s/%s", src_dir, ent->d_name);
1722: snprintf (outfile, 4095, "%s/%s", dest_dir, ent->d_name);
1.1 snw 1723:
1.25 snw 1724: if (stat (outfile, &etcstat) == 0) {
1725: unlink (outfile);
1726: fprintf (stderr, "\tupgrade -> %s\n", ent->d_name);
1727: }
1728: else {
1729: fprintf (stderr, "\tnew -> %s\n", ent->d_name);
1730: }
1731:
1.19 snw 1732: #if !defined(__OS2__)
1733: if (cp (outfile, infile) != 0) {
1734: fprintf (stderr, "fmadm: failure copying %s to %s\n", infile, outfile);
1735: }
1.20 snw 1736: set_permissions (outfile, username, groupname, 0755);
1.19 snw 1737: #else
1738: if (DosCopy (infile, outfile, 1) != 0) {
1739: fprintf (stderr, "fmadm: failure copying %s to %s\n", infile, outfile);
1.1 snw 1740: }
1.19 snw 1741: #endif
1.1 snw 1742:
1743: }
1744:
1745: }
1.20 snw 1746:
1.28 snw 1747: if (fm_validate_environment (fma_environment) == FALSE) {
1748: fp = fopen (env_config_file, "a+");
1749:
1750: fprintf (stderr, "Creating %s... ", env_config_file);
1751:
1752: snprintf (buf, 4095, "[%s]", fma_environment);
1753: fm_write (fp, buf);
1754:
1755: snprintf (buf, 4095, "user=%s", env_user);
1756: fm_write (fp, buf);
1757:
1758: snprintf (buf, 4095, "group=%s", env_group);
1759: fm_write (fp, buf);
1760:
1.29 snw 1761: snprintf (buf, 4095, "enabled=%s", env_enabled);
1.28 snw 1762: fm_write (fp, buf);
1763:
1764: snprintf (buf, 4095, "env_path=%s/freem/%s", LOCALSTATEDIR, fma_environment);
1765: fm_write (fp, buf);
1766:
1767: fclose (fp);
1768: fprintf (stderr, "[OK]\n");
1769: }
1770: else {
1.29 snw 1771: fprintf (stderr, "\nUpdating %s: \n", env_config_file);
1.20 snw 1772:
1.29 snw 1773: update_conf (env_config_file, fma_environment, "user", env_user);
1774: update_conf (env_config_file, fma_environment, "group", env_group);
1775: update_conf (env_config_file, fma_environment, "enabled", env_enabled);
1.28 snw 1776: }
1.29 snw 1777:
1778: if (reconfigure == FALSE) {
1779: fp = fopen (config_file, "a+");
1780:
1781: fprintf (stderr, "Creating %s... ", config_file);
1782:
1783: snprintf (buf, 4095, "[SYSTEM]");
1784: fm_write (fp, buf);
1785:
1786: snprintf (buf, 4095, "root=%s/freem/%s/SYSTEM", LOCALSTATEDIR, fma_environment);
1787: fm_write (fp, buf);
1788:
1789: snprintf (buf, 4095, "routines_path=%s", sysrtn);
1790: fm_write (fp, buf);
1791:
1792: snprintf (buf, 4095, "globals_path=%s", sysgbl);
1793: fm_write (fp, buf);
1794:
1795: snprintf (buf, 4095, "journal_file=%s", jnlfile);
1796: fm_write (fp, buf);
1797:
1798: snprintf (buf, 4095, "journal_mode=%s", jnlmode);
1799: fm_write (fp, buf);
1800:
1801: snprintf (buf, 4095, "journal_host_id=%s", jnlhostid);
1802: fm_write (fp, buf);
1803:
1804: snprintf (buf, 4095, "journal_cut_threshold=%s", jnlcut);
1805: fm_write (fp, buf);
1806:
1807: snprintf (buf, 4095, "zdate_format=%%x");
1808: fm_write (fp, buf);
1809:
1810: snprintf (buf, 4095, "ztime_format=%%X");
1811: fm_write (fp, buf);
1812:
1813: snprintf (buf, 4095, "\n[USER]");
1814: fm_write (fp, buf);
1815:
1816: snprintf (buf, 4095, "root=%s/freem/%s/USER", LOCALSTATEDIR, fma_environment);
1817: fm_write (fp, buf);
1818:
1819: snprintf (buf, 4095, "routines_path=%s", usrrtn);
1820: fm_write (fp, buf);
1821:
1822: snprintf (buf, 4095, "globals_path=%s", usrgbl);
1823: fm_write (fp, buf);
1824:
1825: fclose (fp);
1826: set_permissions (config_file, username, groupname, 0755);
1827: fprintf (stderr, "[OK]\n");
1.1 snw 1828:
1.29 snw 1829: printf ("FreeM initial configuration is complete.\n\n");
1830: }
1831: else {
1832: char tmpsd[255];
1833: read_profile_string (config_file, "SYSTEM", "journal_host_id", tmpsd);
1834:
1835: /* existing configuration */
1836: fprintf (stderr, "\nUpdating environment configuration for %s:\n", fma_environment);
1.1 snw 1837:
1.29 snw 1838: snprintf (buf, 4095, "%s/freem/%s/SYSTEM", LOCALSTATEDIR, fma_environment);
1839: update_conf (config_file, "SYSTEM", "root", buf);
1840: update_conf (config_file, "SYSTEM", "routines_path", sysrtn);
1841: update_conf (config_file, "SYSTEM", "globals_path", sysgbl);
1842: update_conf (config_file, "SYSTEM", "journal_file", jnlfile);
1843: update_conf (config_file, "SYSTEM", "journal_mode", jnlmode);
1844: update_conf (config_file, "SYSTEM", "journal_host_id", tmpsd);
1845: update_conf (config_file, "SYSTEM", "journal_cut_threshold", jnlcut);
1846:
1847: snprintf (buf, 4095, "%%x");
1848: update_conf (config_file, "SYSTEM", "zdate_format", buf);
1849:
1850: snprintf (buf, 4095, "%%X");
1851: update_conf (config_file, "SYSTEM", "ztime_format", buf);
1852:
1853: /* USER */
1854: snprintf (buf, 4095, "%s/freem/%s/USER", LOCALSTATEDIR, fma_environment);
1855: update_conf (config_file, "USER", "root", buf);
1856: update_conf (config_file, "USER", "routines_path", usrrtn);
1857: update_conf (config_file, "USER", "globals_path", usrgbl);
1.1 snw 1858:
1.29 snw 1859: }
1.1 snw 1860:
1.20 snw 1861:
1.29 snw 1862: printf ("\n\nUSER globals: %s\n", usrgbl);
1863: printf ("USER routines: %s\n", usrrtn);
1864: printf ("SYSTEM globals: %s\n", sysgbl);
1865: printf ("SYSTEM routines: %s\n", sysrtn);
1866: printf ("After-image journal: %s [%s]\n", jnlfile, jnlmode);
1867: printf ("Journal cut threshold: %s bytes\n", jnlcut);
1868: printf ("Distributed journaling host ID: %s\n", jnlhostid);
1.1 snw 1869:
1.29 snw 1870: if (reconfigure == TRUE) {
1871: fprintf (stderr, "\nIf you previously defined environments other than '%s', you should run\n'fmadm reconfigure -e=<environment-name>' on each of them to ensure they have\nthe latest vendor routines and correct, updated settings.\n\n", fma_environment);
1872: }
1.1 snw 1873:
1874: } /* fm_configure */
1875:
1.20 snw 1876: void set_permissions(char *path, char *user, char *grp, int mode)
1877: {
1878:
1879: #if !defined(__OS2__)
1880: struct group *d_grp;
1881: struct passwd *d_user;
1882: gid_t d_gid;
1883: uid_t d_uid;
1884: #endif
1885:
1886:
1887: #if !defined(__OS2__)
1888: if ((d_grp = getgrnam (grp)) == NULL) {
1889: fprintf (stderr, "fmadm: '%s' group must exist before configuring\n", grp);
1890: exit (1);
1891: }
1892: d_gid = d_grp->gr_gid;
1893:
1894: if ((d_user = getpwnam (user)) == NULL) {
1895: fprintf (stderr, "fmadm: '%s' user must exist before configuring\n", user);
1896: exit (1);
1897: }
1898: d_uid = d_user->pw_uid;
1899:
1900: if (chown (path, d_uid, d_gid) != 0) {
1901: fprintf (stderr, "fmadm: error setting ownership on %s\n", path);
1902: exit (1);
1903: }
1904: #endif
1905:
1906: if (chmod (path, mode) != 0) {
1907: fprintf (stderr, "fmadm: error setting permissions on %s to %d\n", path, mode);
1908: exit (1);
1909: }
1910:
1911: }
1912:
1.1 snw 1913: void fm_write (FILE *file, char *buf)
1914: {
1915: fprintf (file, "%s\n", buf);
1916: }
1917:
1918: void fm_sig_attach (int sig, void *handler)
1919: {
1920: struct sigaction act;
1921:
1922: act.sa_handler = handler;
1923: sigaction (sig, &act, NULL);
1924:
1925: }
1926:
1927: void fm_sig_init (void)
1928: {
1929: sig_attach (SIGINT, &fm_on_sigint);
1930: sig_attach (SIGTERM, &fm_on_sigterm);
1931: }
1932:
1933: void fm_on_sigint (void)
1934: {
1935: fprintf (stderr, "\nfmadm: caught SIGINT\n");
1936: fmadm_exit (0);
1937: }
1938:
1939: void fm_on_sigterm (void)
1940: {
1941: fprintf (stderr, "\nfmadm: caught SIGTERM\n");
1942: fmadm_exit (0);
1943: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>