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