Annotation of freem/src/init.c, revision 1.13
1.1 snw 1: /*
1.13 ! snw 2: * $Id: init.c,v 1.12 2025/04/15 14:39:06 snw Exp $
1.1 snw 3: * FreeM initialization
4: *
5: *
1.5 snw 6: * Author: Serena Willis <snw@coherent-logic.com>
1.1 snw 7: * Copyright (C) 1998 MUG Deutschland
1.6 snw 8: * Copyright (C) 2020, 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.7 snw 26: * $Log: init.c,v $
1.13 ! snw 27: * Revision 1.12 2025/04/15 14:39:06 snw
! 28: * Further improvements to logging
! 29: *
1.12 snw 30: * Revision 1.11 2025/04/13 04:22:43 snw
31: * Fix snprintf calls
32: *
1.11 snw 33: * Revision 1.10 2025/04/10 01:24:38 snw
34: * Remove C++ style comments
35: *
1.10 snw 36: * Revision 1.9 2025/04/03 16:58:34 snw
37: * Make error message for shm_init error during initialization more friendly
38: *
1.9 snw 39: * Revision 1.8 2025/03/24 04:44:55 snw
40: * Don't call ttyname on OS/2
41: *
1.8 snw 42: * Revision 1.7 2025/03/24 04:05:36 snw
43: * Replace crlf with frm_crlf to avoid symbol conflict with readline on OS/2
44: *
1.7 snw 45: * Revision 1.6 2025/03/09 19:14:25 snw
46: * First phase of REUSE compliance and header reformat
47: *
1.6 snw 48: *
49: * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
50: * SPDX-License-Identifier: AGPL-3.0-or-later
1.1 snw 51: **/
52:
53: #include <stdio.h>
54: #include <stdlib.h>
55: #include <string.h>
56: #include <unistd.h>
57: #include <limits.h>
58: #include <sys/types.h>
59: #include <sys/stat.h>
60: #include <pwd.h>
61: #include <time.h>
62: #include <errno.h>
63: #include <sys/ioctl.h>
1.2 snw 64:
1.4 snw 65: #if !defined(__APPLE__) && !defined(__gnu_hurd__) && !defined(EMSCRIPTEN)
66: # if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__AMIGA)
67: # include <termios.h>
68: # if !defined(__AMIGA)
69: # define TCGETA TIOCGETA
70: # define TCSETA TIOCSETA
71: # endif
72: # define termio termios
73: # else
74: # if !defined(MSDOS)
75: # include <termio.h>
76: # endif
77: # endif
1.2 snw 78: #else
79: # include <termios.h>
80: #endif
1.1 snw 81:
82: #include "config.h"
83:
84: #if defined(HAVE_MWAPI_MOTIF)
85: # include <Xm/Xm.h>
86: #endif
87:
88: #include "mpsdef.h"
89: #include "transact.h"
90: #include "namespace.h"
91: #include "events.h"
92: #include "mdebug.h"
93: #include "shmmgr.h"
94: #include "locktab.h"
95: #include "jobtab.h"
96: #include "datatypes.h"
97: #include "objects.h"
1.12 snw 98: #include "log.h"
1.1 snw 99:
100: #ifdef HAVE_LIBREADLINE
101: # if defined(HAVE_READLINE_READLINE_H)
102: # include <readline/readline.h>
103: # elif defined(HAVE_READLINE_H)
104: # include <readline.h>
105: # else /* !defined(HAVE_READLINE_H) */
106: extern char *readline ();
107: # endif /* !defined(HAVE_READLINE_H) */
108: char *cmdline = NULL;
109: #else /* !defined(HAVE_READLINE_READLINE_H) */
110: /* no readline */
111: #endif /* HAVE_LIBREADLINE */
112:
113: #ifdef HAVE_READLINE_HISTORY
114: # if defined(HAVE_READLINE_HISTORY_H)
115: # include <readline/history.h>
116: # elif defined(HAVE_HISTORY_H)
117: # include <history.h>
118: # else /* !defined(HAVE_HISTORY_H) */
119: extern void add_history ();
120: extern int write_history ();
121: extern int read_history ();
122: # endif /* defined(HAVE_READLINE_HISTORY_H) */
123: /* no history */
124: #endif /* HAVE_READLINE_HISTORY */
125:
126: #if defined(HAVE_WIRINGPI_H)
127: # include <wiringPi.h>
128: #endif
129:
130: #if !defined(PATH_MAX) && defined(_SCO_DS)
131: # define PATH_MAX 4096
132: #endif
133:
134: #if !defined(PATH_MAX) && defined(__gnu_hurd__)
135: # define PATH_MAX 1024
136: #endif
137:
138: #if !defined(PATH_MAX) && defined(__sun__)
139: # include <limits.h>
140: #endif
141:
142: #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
143: # include <sys/syslimits.h>
144: #endif
145:
146: #define SHMKEY 0x990120
147: #define SHMSIZ 1048576
148:
149: void init_process(void);
150: void init_devtable(void);
151: void init_signals(void);
152: void init_timezone(void);
153: void init_freem_path(void);
154:
155: #if defined(HAVE_LIBREADLINE)
156: void init_readline(void);
157: #endif
158:
159: void init_execution_context(void);
160: void init_io(void);
161: void init_random_number(void);
162: void init_ztrap(void);
163: void init_ssvn(void);
164: void init_terminal(void);
165: void init_estack(void);
166:
167: void init_mwapi(void);
168:
169: short init (char *namespace_name)
170: {
171: short retval;
1.13 ! snw 172: int log_level;
! 173:
1.12 snw 174: init_log ();
1.1 snw 175: init_process ();
176: init_devtable ();
177: init_signals ();
178: init_freem_path ();
179: init_timezone ();
180:
181: #if defined(HAVE_LIBREADLINE)
182: init_readline ();
183: #endif
184:
185: init_execution_context ();
186:
187: if (run_daemon == FALSE) {
188: init_io ();
189: }
190:
191: init_random_number ();
192: init_ztrap ();
193:
194: retval = shm_init (shm_init_size);
195:
196: if (retval == SHMS_GET_ERR) {
1.9 snw 197: if (errno != 13) {
1.13 ! snw 198: logprintf (FM_LOG_FATAL, "init: error initializing shared memory (error code %d [%s])", errno, strerror (errno));
1.9 snw 199: }
200: else {
1.13 ! snw 201: logprintf (FM_LOG_FATAL, "init: error attaching to environment -- does your user belong to the group that owns environment '%s'?", shm_env);
1.9 snw 202: }
1.1 snw 203: }
204:
205: symtab_init ();
206: tp_init ();
207:
208: set_namespace (namespace_name, FALSE);
209:
210: if (first_process) {
1.13 ! snw 211: log_level = FM_LOG_INFO;
! 212: }
! 213: else {
! 214: log_level = FM_LOG_DEBUG;
! 215: }
! 216:
! 217: if (first_process) {
! 218: logprintf (log_level, "init: we are the first process in the environment (pid %d)", pid);
1.1 snw 219: }
220:
1.13 ! snw 221: logprintf (log_level, "init: initializing job table");
1.1 snw 222: jobtab_init ();
223:
1.13 ! snw 224: logprintf (log_level, "init: adding job to job table");
1.1 snw 225: job_init (FALSE);
226:
1.13 ! snw 227: logprintf (log_level, "init: initializing structured system variables");
1.1 snw 228: init_ssvn ();
229:
1.13 ! snw 230: logprintf (log_level, "init: initializing terminal");
1.1 snw 231: init_terminal ();
232:
1.13 ! snw 233: logprintf (log_level, "init: initializing asynchronous events");
1.1 snw 234: evt_init ();
235:
1.13 ! snw 236: logprintf (log_level, "init: initializing debugger");
1.1 snw 237: dbg_init ();
238:
1.13 ! snw 239: logprintf (log_level, "init: initializing error stack");
1.1 snw 240: init_estack();
241:
242: etrap[0] = EOL;
243: ecode[0] = EOL;
244: estack = 0;
245:
246: init_mwapi();
247:
248: if (merr () == OK) {
249: return TRUE;
250: }
251:
252: return FALSE;
253: }
254:
255: void init_process (void)
256: {
257: pid = getpid (); /* get $J = process ID */
258: umask (0); /* protection bits mask to full rights */
1.11 snw 259: snprintf (fp_conversion, sizeof (fp_conversion) - 1, "%%.%df\201", DBL_DIG);
1.1 snw 260:
261: if (fp_mode) {
262: zprecise = DBL_DIG;
263: }
264: else {
265: zprecise = 100;
266: }
267: }
268:
269: void init_devtable (void)
270: {
271: register int i;
272: register int j;
273:
274: for (j = 0; j <= MAXDEV; j++) { /* init. translation tables */
275:
276: for (i = 0; i < 256; i++) {
277: G0I[j][i] = (char) i;
278: G0O[j][i] = (char) i;
279: G1I[j][i] = (char) i;
280: G1O[j][i] = (char) i;
281: }
282:
283: G0I[j][UNSIGN (EOL)] = NUL;
284: G0O[j][UNSIGN (EOL)] = NUL;
285: G1I[j][UNSIGN (EOL)] = NUL;
286: G1O[j][UNSIGN (EOL)] = NUL;
287: G0I[j][UNSIGN (DELIM)] = NUL;
288: G0O[j][UNSIGN (DELIM)] = NUL;
289: G1I[j][UNSIGN (DELIM)] = NUL;
290: G1O[j][UNSIGN (DELIM)] = NUL;
291: G0I[j][256] = EOL;
292: G0O[j][256] = EOL;
293: G1I[j][256] = EOL;
294: G1O[j][256] = EOL;
295:
296: }
297:
298: #ifdef SCO
299: #ifndef HACK_NOXLATE
300: G0I[HOME][245] = 64;
301: G0O[HOME][64] = 245; /* Paragraph */
302: G0I[HOME][142] = 91;
303: G0O[HOME][91] = 142; /* A umlaut */
304: G0I[HOME][153] = 92;
305: G0O[HOME][92] = 153; /* O umlaut */
306: G0I[HOME][154] = 93;
307: G0O[HOME][93] = 154; /* U umlaut */
308: G0I[HOME][132] = 123;
309: G0O[HOME][123] = 132; /* a umlaut */
310: G0I[HOME][148] = 124;
311: G0O[HOME][124] = 148; /* o umlaut */
312: G0I[HOME][129] = 125;
313: G0O[HOME][125] = 129; /* u umlaut */
314: G0I[HOME][225] = 126;
315: G0O[HOME][126] = 225; /* sharp s */
316: #endif/*HACK_NOXLATE*/
317:
318: /* DEC Special graphics */
319: G1I[HOME][254] = 96;
320: G1O[HOME][96] = 254; /* diamond */
321: G1I[HOME][176] = 97;
322: G1O[HOME][97] = 176; /* checker board */
323: G1I[HOME][241] = 99;
324: G1O[HOME][99] = 241; /* FF */
325: G1I[HOME][242] = 100;
326: G1O[HOME][100] = 242; /* CR */
327: G1I[HOME][243] = 101;
328: G1O[HOME][101] = 243; /* LF */
329: G1I[HOME][248] = 102;
330: G1O[HOME][102] = 248; /* degree sign */
331: G1I[HOME][241] = 103;
332: G1O[HOME][103] = 241; /* plus minus */
333: G1I[HOME][244] = 104;
334: G1O[HOME][104] = 244; /* NL */
335: G1I[HOME][251] = 105;
336: G1O[HOME][105] = 251; /* VT */
337: G1I[HOME][217] = 106;
338: G1O[HOME][106] = 217; /* lower right corner */
339: G1I[HOME][191] = 107;
340: G1O[HOME][107] = 191; /* upper right corner */
341: G1I[HOME][218] = 108;
342: G1O[HOME][108] = 218; /* upper left corner */
343: G1I[HOME][192] = 109;
344: G1O[HOME][109] = 192; /* lower left corner */
345: G1I[HOME][197] = 110;
346: G1O[HOME][110] = 197; /* cross */
347: G1I[HOME][200] = 111;
348: G1O[HOME][111] = 200; /* linescan 5 */
349: G1I[HOME][201] = 112;
350: G1O[HOME][112] = 201; /* linescan 4 */
351: G1I[HOME][196] = 113;
352: G1O[HOME][113] = 196; /* linescan 3 */
353: G1I[HOME][202] = 114;
354: G1O[HOME][114] = 202; /* linescan 2 */
355: G1I[HOME][203] = 115;
356: G1O[HOME][115] = 203; /* linescan 1 */
357: G1I[HOME][195] = 116;
358: G1O[HOME][116] = 195; /* left junction */
359: G1I[HOME][180] = 117;
360: G1O[HOME][117] = 180; /* right junction */
361: G1I[HOME][193] = 118;
362: G1O[HOME][118] = 193; /* lower junction */
363: G1I[HOME][194] = 119;
364: G1O[HOME][119] = 194; /* upper junction */
365: G1I[HOME][179] = 120;
366: G1O[HOME][120] = 179; /* vertival bar */
367: G1I[HOME][243] = 121;
368: G1O[HOME][121] = 243; /* lower equals */
369: G1I[HOME][242] = 122;
370: G1O[HOME][122] = 242; /* greater equals */
371: G1I[HOME][227] = 123;
372: G1O[HOME][123] = 227; /* pi */
373: G1I[HOME][246] = 124;
374: G1O[HOME][124] = 246; /* not equals */
375: G1I[HOME][128] = 125;
376: G1O[HOME][125] = 128; /* euro sign */
377: G1I[HOME][250] = 126;
378: G1O[HOME][126] = 250; /* centered dot */
379: #endif /* SCO */
380: }
381:
382: void init_signals (void)
383: {
384: sig_init ();
385: }
386:
387: void init_timezone (void)
388: {
389:
390: struct tm lt;
391: struct tm gt;
392:
393: unsigned long gmt;
394: unsigned long lmt;
395:
396: long clock;
397:
398: #ifdef __CYGWIN__
399:
400: tzset (); /* may be required in order */
401: /* to guarantee _timezone set */
402: #else
403:
404: clock = time (0L);
405: lt = *localtime (&clock);
406: gt = *gmtime (&clock);
407:
408: /* This is awkward but I think it is portable: steve_morris */
409: gmt = gt.tm_year * 365;
410: gmt = (gmt + gt.tm_yday) * 24;
411: gmt = (gmt + gt.tm_hour) * 60;
412: gmt = (gmt + gt.tm_min);
413:
414: lmt = lt.tm_year * 365;
415: lmt = (lmt + lt.tm_yday) * 24;
416: lmt = (lmt + lt.tm_hour) * 60;
417: lmt = (lmt + lt.tm_min);
418:
419: FreeM_timezone = (gmt - lmt) * 60;
420: tzoffset = -FreeM_timezone;
421:
422: #endif /* __CYGWIN__ */
423:
424:
425: }
426:
427: void init_freem_path (void)
428: {
429:
430: if((freem_path = malloc(PATH_MAX + 1)) == NULL) {
431: fprintf(stderr, "Can't allocate freem_path. Exiting.");
432:
433: exit(1);
434: }
435:
436: freem_path[0] = NUL;
437:
438: /* check where I'm being executed from */
439: #ifdef __linux__
440: readlink ("/proc/self/exe", freem_path, PATH_MAX);
441: #endif
442: #ifdef __FreeBSD__
443: readlink ("/proc/curproc/file", freem_path, PATH_MAX);
444: #endif
445: #ifdef __sun
446: readlink ("/proc/self/path/a.out", freem_path, PATH_MAX);
447: #endif
448:
449: if(freem_path[0] == NUL) {
450: /* we don't know where we came from */
451: }
452:
453: getcwd (curdir, PATHLEN);
454: stcnv_c2m (curdir);
455:
456: }
457:
458: #if defined(HAVE_LIBREADLINE)
459: void init_readline (void)
460: {
461: uid_t uid = geteuid ();
462: struct passwd *pw = getpwuid (uid);
463: char *pw_buf;
464:
465: pw_buf = (char *) calloc (strlen(pw->pw_dir) + 1, sizeof(char));
466: strcpy (pw_buf, pw->pw_dir);
467:
1.11 snw 468: snprintf (history_file, sizeof (history_file) - 1, "%s/.freem_history", pw_buf);
1.1 snw 469:
470: free (pw_buf);
471:
472: using_history ();
473: read_history (history_file);
474: }
475: #endif
476:
477: void init_execution_context (void)
478: {
479: register int i;
480:
481: obj_init ();
482:
483: merr_clear ();
484:
485: codptr = code;
486: code[0] = EOL; /* init code_pointer */
487: partition = calloc ((unsigned) (PSIZE + 2), 1);
488:
489: if (partition == NULL) exit (2); /* could not allocate stuff... */
490:
491: for (i = 0; i < MAXNO_OF_RBUF; i++) {
492: rbuf_flags[i].standard = standard;
493: }
494:
495: for (i = 0; i < NESTLEVLS; i++) {
496: extr_types[i] = DT_STRING;
497: }
498:
499: symlen = PSIZE;
500: s = &partition[PSIZE] - 256; /* pointer to symlen_offset */
501: argptr = partition; /* pointer to beg of tmp-storage */
502:
503: svntable = calloc ((unsigned) (UDFSVSIZ + 1), 1);
504: if (svntable == NULL) exit (2); /* could not allocate stuff... */
505:
506: svnlen = UDFSVSIZ; /* begin of udf_svn_table */
507: buff = calloc ((unsigned) NO_OF_RBUF * (unsigned) PSIZE0, 1); /* routine buffer pool */
508: if (buff == NULL) exit (2); /* could not allocate stuff... */
509:
510:
511: newstack = calloc ((unsigned) NSIZE, 1);
512: if (newstack == NULL) exit (2); /* could not allocate stuff... */
513:
514: #ifdef DEBUG_NEWPTR
515: printf("Allocating newptr stack...\r\n");
516: #endif
517:
518: newptr = newstack;
519: newlimit = newstack + NSIZE - 1024;
520:
521:
522: namstck = calloc ((unsigned) NESTLEVLS * 13, 1);
523: if (namstck == NULL) exit (2); /* could not allocate stuff... */
524:
525: *namstck = EOL;
526: *(namstck + 1) = EOL;
527: namptr = namstck; /* routine name stack pointer */
528: framstck = calloc ((unsigned) NESTLEVLS * 256, 1);
529: if (framstck == NULL) exit (2); /* could not allocate stuff... */
530:
531: *framstck = EOL;
532: *(framstck + 1) = EOL;
533: dofrmptr = framstck; /* DO_frame stack pointer */
534: cmdstack = calloc ((unsigned) NESTLEVLS * 256, 1);
535: if (cmdstack == NULL) exit (2); /* could not allocate stuff... */
536:
537: cmdptr = cmdstack; /* command stack */
538:
539: rouend = rouins = rouptr = buff;
540: roucur = buff + (NO_OF_RBUF * PSIZE0 + 1);
541: *rouptr = EOL;
542: *(rouptr + 1) = EOL;
543: *(rouptr + 2) = EOL;
544:
545: err_suppl[0] = EOL; /* empty out supplemental error info */
546: }
547:
548: void init_estack (void)
549: {
550: stcpy (merr_stack[0].PLACE, "xecline()\201");
551: }
552:
553: #if defined(HAVE_MWAPI_MOTIF)
554: void init_mwapi (void)
555: {
556: /*
557: if (getenv("DISPLAY") != NULL) {
558: gtk_init (0, NULL);
559: }
560: */
1.10 snw 561: /* TODO: init Motif/libXt */
1.1 snw 562: }
563: #else
564: void init_mwapi (void)
565: {
566: return;
567: }
568: #endif
569:
570: void init_io (void)
571: {
572: register int i;
573:
574: /* initialize screen */
575: setbuf (stdin, NULL); /* no input buffering */
576: glvnflag.all = 0L;
577: stcpy (buff, "\201");
578: writeHOME (buff);
579: sq_modes[0] = '+';
580: for (i = 0; i <= MAXDEV; ug_buf[i++][0] = EOL); /* init read-buffers */
581:
1.7 snw 582: frm_crlf[HOME] = frm_filter;
1.1 snw 583:
584: if (hardcopy) zbreakon = ENABLE; /* enable CTRL/B */
585:
586: set_io (MUMPS); /* set i/o parameters */
587:
1.8 snw 588: #if !defined(__AMIGA) && !defined(__OS2__)
1.1 snw 589: if (ttyname (HOME)) { /* for $IO of HOME */
590: strcpy (dev[HOME], ttyname (HOME));
591: dev[HOME][strlen (dev[HOME])] = EOL;
592: }
593: else {
594: dev[HOME][0] = EOL; /* ...we are in a pipe */
595: }
596: #else
1.8 snw 597: #if defined(__AMIGA)
1.1 snw 598: strcpy (dev[HOME], "CONSOLE:");
1.8 snw 599: #else
600: #if defined(__OS2__)
601: strcpy (dev[HOME], "CON:");
602: #endif
603: #endif
1.1 snw 604: #endif
605:
606: /* init function keys */
607: for (i = 0; i < 44; zfunkey[i++][0] = EOL);
608: }
609:
610: void init_random_number (void)
611: {
612:
613: srand (time (NULL));
614:
615: if ((nrandom = time (0L) * getpid ()) < 0) {
616: nrandom = (-nrandom);
617: }
618:
619: }
620:
621: void init_ztrap (void)
622: {
623:
624: if (frm_filter) {
625: ztrap[0][0] = EOL; /* no default ztrap for filters */
626: }
627: else if (startuprou[0] == '^') {
628: stcpy (ztrap[0], startuprou);
629: }
630: else {
631: stcpy (ztrap[0], "^%SYSINIT\201");
632: }
633:
634: /* $ZT to be xecuted on startup */
635:
636: stcpy (ztrap[NESTLEVLS + 1], ztrap[0]); /* DSM V.2 error trapping */
637:
638: }
639:
640: void init_ssvn(void)
641: {
642: ssvn_job_update ();
643: ssvn_display_update ();
644: ssvn_routine_update ();
645: ssvn_library_update ();
646: if (first_process) ssvn_system_update ();
647: }
648:
649: void init_terminal(void)
650: {
651: xpos[HOME] = 80;
652: ypos[HOME] = 24;
653: }
654:
655: void reset_terminal(void)
656: {
657: struct termio tpara;
658:
659: ioctl (0, TCGETA, &tpara);
660:
661: tpara.c_lflag |= (ECHO | ICANON); /* enable echo/no cbreak mode */
662: tpara.c_iflag |= ICRNL; /* cr-lf mapping */
663: tpara.c_oflag |= ONLCR; /* cr-lf mapping */
664: tpara.c_cc[VMIN] = EOT;
665: tpara.c_cc[VTIME] = -1;
666:
667: ioctl (0, TCSETA, &tpara);
668: }
669:
670: void cleanup (void)
671: {
672: char k_buf[256];
673: int ch;
674:
675: /* remove this job's entry from ^$JOB SSVN */
1.11 snw 676: snprintf (k_buf, sizeof (k_buf) - 1, "^$JOB\202%d\201", pid);
1.1 snw 677: symtab_shm (kill_sym, k_buf, " \201");
678:
679: reset_terminal ();
680:
681: if (tp_level > 0) {
682:
683: if (direct_mode == TRUE) {
684: fprintf (stderr, "UNCOMMITTED TRANSACTIONS EXIST:\n\n");
685: tp_tdump ();
686: set_io (UNIX);
687: fprintf (stderr, "\nWould you like to c)ommit or r)ollback the above transactions and their operations? ($TLEVEL = %d) ", tp_level);
688:
689: for (;;) {
690: ch = fgetc (stdin);
691:
692: if (ch == 'c' || ch == 'C') {
693: while (tp_level > 0) tp_tcommit ();
694:
695: fprintf (stderr, "\n\nTransactions have been committed.\n");
696:
697: break;
698: }
699: else if (ch == 'r' || ch == 'R') {
700: tp_trollback (tp_level);
701:
702: fprintf (stderr, "\n\nTransactions have been rolled back.\n");
703:
704: break;
705: }
706: else {
707: fprintf (stderr, "\n\nInvalid input '%c'. Must choose c)ommit or r)ollback.\n", ch);
708: }
709: }
710: }
711: else {
712: fprintf (stderr, "Uncommitted transactions exist. Rolling back.\n");
713: tp_trollback (tp_level);
714: }
715: }
716:
717: #if defined(HAVE_LIBREADLINE)
718: write_history (history_file);
719: #endif
720:
721: locktab_unlock_all ();
722: job_remove (pid);
723:
724: shm_exit ();
725:
726: if (run_daemon == TRUE) {
727:
728: if (pid_fd != -1) {
729: lockf (pid_fd, F_ULOCK, 0);
730: close (pid_fd);
731: }
732:
733: if (pid_file_path != NULL) {
734: unlink (pid_file_path);
735: }
736:
737: }
738:
739:
740:
741: free (buff); /* free previously allocated space */
742: free (svntable);
743: if (partition) free (partition);
744: if (apartition) free (apartition);
745:
746:
747: free (newstack);
748:
749:
750: if (v22size) free (v22ali);
751:
752: return;
753: } /* end of cleanup */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>