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