/*
* $Id: init.c,v 1.8 2025/03/24 04:44:55 snw Exp $
* FreeM initialization
*
*
* Author: Serena Willis <snw@coherent-logic.com>
* Copyright (C) 1998 MUG Deutschland
* Copyright (C) 2020, 2025 Coherent Logic Development LLC
*
*
* This file is part of FreeM.
*
* FreeM is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FreeM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero Public License for more details.
*
* You should have received a copy of the GNU Affero Public License
* along with FreeM. If not, see <https://www.gnu.org/licenses/>.
*
* $Log: init.c,v $
* Revision 1.8 2025/03/24 04:44:55 snw
* Don't call ttyname on OS/2
*
* Revision 1.7 2025/03/24 04:05:36 snw
* Replace crlf with frm_crlf to avoid symbol conflict with readline on OS/2
*
* Revision 1.6 2025/03/09 19:14:25 snw
* First phase of REUSE compliance and header reformat
*
*
* SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
* SPDX-License-Identifier: AGPL-3.0-or-later
**/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <time.h>
#include <errno.h>
#include <sys/ioctl.h>
#if !defined(__APPLE__) && !defined(__gnu_hurd__) && !defined(EMSCRIPTEN)
# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__AMIGA)
# include <termios.h>
# if !defined(__AMIGA)
# define TCGETA TIOCGETA
# define TCSETA TIOCSETA
# endif
# define termio termios
# else
# if !defined(MSDOS)
# include <termio.h>
# endif
# endif
#else
# include <termios.h>
#endif
#include "config.h"
#if defined(HAVE_MWAPI_MOTIF)
# include <Xm/Xm.h>
#endif
#include "mpsdef.h"
#include "transact.h"
#include "namespace.h"
#include "events.h"
#include "mdebug.h"
#include "shmmgr.h"
#include "locktab.h"
#include "jobtab.h"
#include "datatypes.h"
#include "objects.h"
#ifdef HAVE_LIBREADLINE
# if defined(HAVE_READLINE_READLINE_H)
# include <readline/readline.h>
# elif defined(HAVE_READLINE_H)
# include <readline.h>
# else /* !defined(HAVE_READLINE_H) */
extern char *readline ();
# endif /* !defined(HAVE_READLINE_H) */
char *cmdline = NULL;
#else /* !defined(HAVE_READLINE_READLINE_H) */
/* no readline */
#endif /* HAVE_LIBREADLINE */
#ifdef HAVE_READLINE_HISTORY
# if defined(HAVE_READLINE_HISTORY_H)
# include <readline/history.h>
# elif defined(HAVE_HISTORY_H)
# include <history.h>
# else /* !defined(HAVE_HISTORY_H) */
extern void add_history ();
extern int write_history ();
extern int read_history ();
# endif /* defined(HAVE_READLINE_HISTORY_H) */
/* no history */
#endif /* HAVE_READLINE_HISTORY */
#if defined(HAVE_WIRINGPI_H)
# include <wiringPi.h>
#endif
#if !defined(PATH_MAX) && defined(_SCO_DS)
# define PATH_MAX 4096
#endif
#if !defined(PATH_MAX) && defined(__gnu_hurd__)
# define PATH_MAX 1024
#endif
#if !defined(PATH_MAX) && defined(__sun__)
# include <limits.h>
#endif
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
# include <sys/syslimits.h>
#endif
#define SHMKEY 0x990120
#define SHMSIZ 1048576
void init_process(void);
void init_devtable(void);
void init_signals(void);
void init_timezone(void);
void init_freem_path(void);
#if defined(HAVE_LIBREADLINE)
void init_readline(void);
#endif
void init_execution_context(void);
void init_io(void);
void init_random_number(void);
void init_ztrap(void);
void init_ssvn(void);
void init_terminal(void);
void init_estack(void);
void init_mwapi(void);
short init (char *namespace_name)
{
short retval;
init_process ();
init_devtable ();
init_signals ();
init_freem_path ();
init_timezone ();
#if defined(HAVE_LIBREADLINE)
init_readline ();
#endif
init_execution_context ();
if (run_daemon == FALSE) {
init_io ();
}
init_random_number ();
init_ztrap ();
retval = shm_init (shm_init_size);
if (retval == SHMS_GET_ERR) {
fprintf (stderr, "init: error initializing shared memory [errno %d]\r\n", errno);
exit (1);
}
symtab_init ();
tp_init ();
set_namespace (namespace_name, FALSE);
if (first_process) {
fprintf (stderr, "init: we are the first process in the environment (pid %d)\r\n", pid);
}
if (first_process) fprintf (stderr, "init: initializing job table\r\n");
jobtab_init ();
if (first_process) fprintf (stderr, "init: adding job to job table\r\n");
job_init (FALSE);
if (first_process) fprintf (stderr, "init: initializing structured system variables\r\n");
init_ssvn ();
if (first_process) fprintf (stderr, "init: initializing terminal\r\n");
init_terminal ();
if (first_process) fprintf (stderr, "init: initializing asynchronous events\r\n");
evt_init ();
if (first_process) fprintf (stderr, "init: initializing debugger\r\n");
dbg_init ();
if (first_process) fprintf (stderr, "init: initializing error stack\r\n");
init_estack();
etrap[0] = EOL;
ecode[0] = EOL;
estack = 0;
init_mwapi();
if (merr () == OK) {
return TRUE;
}
return FALSE;
}
void init_process (void)
{
pid = getpid (); /* get $J = process ID */
umask (0); /* protection bits mask to full rights */
snprintf (fp_conversion, 9, "%%.%df\201", DBL_DIG);
if (fp_mode) {
zprecise = DBL_DIG;
}
else {
zprecise = 100;
}
}
void init_devtable (void)
{
register int i;
register int j;
for (j = 0; j <= MAXDEV; j++) { /* init. translation tables */
for (i = 0; i < 256; i++) {
G0I[j][i] = (char) i;
G0O[j][i] = (char) i;
G1I[j][i] = (char) i;
G1O[j][i] = (char) i;
}
G0I[j][UNSIGN (EOL)] = NUL;
G0O[j][UNSIGN (EOL)] = NUL;
G1I[j][UNSIGN (EOL)] = NUL;
G1O[j][UNSIGN (EOL)] = NUL;
G0I[j][UNSIGN (DELIM)] = NUL;
G0O[j][UNSIGN (DELIM)] = NUL;
G1I[j][UNSIGN (DELIM)] = NUL;
G1O[j][UNSIGN (DELIM)] = NUL;
G0I[j][256] = EOL;
G0O[j][256] = EOL;
G1I[j][256] = EOL;
G1O[j][256] = EOL;
}
#ifdef SCO
#ifndef HACK_NOXLATE
G0I[HOME][245] = 64;
G0O[HOME][64] = 245; /* Paragraph */
G0I[HOME][142] = 91;
G0O[HOME][91] = 142; /* A umlaut */
G0I[HOME][153] = 92;
G0O[HOME][92] = 153; /* O umlaut */
G0I[HOME][154] = 93;
G0O[HOME][93] = 154; /* U umlaut */
G0I[HOME][132] = 123;
G0O[HOME][123] = 132; /* a umlaut */
G0I[HOME][148] = 124;
G0O[HOME][124] = 148; /* o umlaut */
G0I[HOME][129] = 125;
G0O[HOME][125] = 129; /* u umlaut */
G0I[HOME][225] = 126;
G0O[HOME][126] = 225; /* sharp s */
#endif/*HACK_NOXLATE*/
/* DEC Special graphics */
G1I[HOME][254] = 96;
G1O[HOME][96] = 254; /* diamond */
G1I[HOME][176] = 97;
G1O[HOME][97] = 176; /* checker board */
G1I[HOME][241] = 99;
G1O[HOME][99] = 241; /* FF */
G1I[HOME][242] = 100;
G1O[HOME][100] = 242; /* CR */
G1I[HOME][243] = 101;
G1O[HOME][101] = 243; /* LF */
G1I[HOME][248] = 102;
G1O[HOME][102] = 248; /* degree sign */
G1I[HOME][241] = 103;
G1O[HOME][103] = 241; /* plus minus */
G1I[HOME][244] = 104;
G1O[HOME][104] = 244; /* NL */
G1I[HOME][251] = 105;
G1O[HOME][105] = 251; /* VT */
G1I[HOME][217] = 106;
G1O[HOME][106] = 217; /* lower right corner */
G1I[HOME][191] = 107;
G1O[HOME][107] = 191; /* upper right corner */
G1I[HOME][218] = 108;
G1O[HOME][108] = 218; /* upper left corner */
G1I[HOME][192] = 109;
G1O[HOME][109] = 192; /* lower left corner */
G1I[HOME][197] = 110;
G1O[HOME][110] = 197; /* cross */
G1I[HOME][200] = 111;
G1O[HOME][111] = 200; /* linescan 5 */
G1I[HOME][201] = 112;
G1O[HOME][112] = 201; /* linescan 4 */
G1I[HOME][196] = 113;
G1O[HOME][113] = 196; /* linescan 3 */
G1I[HOME][202] = 114;
G1O[HOME][114] = 202; /* linescan 2 */
G1I[HOME][203] = 115;
G1O[HOME][115] = 203; /* linescan 1 */
G1I[HOME][195] = 116;
G1O[HOME][116] = 195; /* left junction */
G1I[HOME][180] = 117;
G1O[HOME][117] = 180; /* right junction */
G1I[HOME][193] = 118;
G1O[HOME][118] = 193; /* lower junction */
G1I[HOME][194] = 119;
G1O[HOME][119] = 194; /* upper junction */
G1I[HOME][179] = 120;
G1O[HOME][120] = 179; /* vertival bar */
G1I[HOME][243] = 121;
G1O[HOME][121] = 243; /* lower equals */
G1I[HOME][242] = 122;
G1O[HOME][122] = 242; /* greater equals */
G1I[HOME][227] = 123;
G1O[HOME][123] = 227; /* pi */
G1I[HOME][246] = 124;
G1O[HOME][124] = 246; /* not equals */
G1I[HOME][128] = 125;
G1O[HOME][125] = 128; /* euro sign */
G1I[HOME][250] = 126;
G1O[HOME][126] = 250; /* centered dot */
#endif /* SCO */
}
void init_signals (void)
{
sig_init ();
}
void init_timezone (void)
{
struct tm lt;
struct tm gt;
unsigned long gmt;
unsigned long lmt;
long clock;
#ifdef __CYGWIN__
tzset (); /* may be required in order */
/* to guarantee _timezone set */
#else
clock = time (0L);
lt = *localtime (&clock);
gt = *gmtime (&clock);
/* This is awkward but I think it is portable: steve_morris */
gmt = gt.tm_year * 365;
gmt = (gmt + gt.tm_yday) * 24;
gmt = (gmt + gt.tm_hour) * 60;
gmt = (gmt + gt.tm_min);
lmt = lt.tm_year * 365;
lmt = (lmt + lt.tm_yday) * 24;
lmt = (lmt + lt.tm_hour) * 60;
lmt = (lmt + lt.tm_min);
FreeM_timezone = (gmt - lmt) * 60;
tzoffset = -FreeM_timezone;
#endif /* __CYGWIN__ */
}
void init_freem_path (void)
{
if((freem_path = malloc(PATH_MAX + 1)) == NULL) {
fprintf(stderr, "Can't allocate freem_path. Exiting.");
exit(1);
}
freem_path[0] = NUL;
/* check where I'm being executed from */
#ifdef __linux__
readlink ("/proc/self/exe", freem_path, PATH_MAX);
#endif
#ifdef __FreeBSD__
readlink ("/proc/curproc/file", freem_path, PATH_MAX);
#endif
#ifdef __sun
readlink ("/proc/self/path/a.out", freem_path, PATH_MAX);
#endif
if(freem_path[0] == NUL) {
/* we don't know where we came from */
}
getcwd (curdir, PATHLEN);
stcnv_c2m (curdir);
}
#if defined(HAVE_LIBREADLINE)
void init_readline (void)
{
uid_t uid = geteuid ();
struct passwd *pw = getpwuid (uid);
char *pw_buf;
pw_buf = (char *) calloc (strlen(pw->pw_dir) + 1, sizeof(char));
strcpy (pw_buf, pw->pw_dir);
snprintf (history_file, 256, "%s/.freem_history", pw_buf);
free (pw_buf);
using_history ();
read_history (history_file);
}
#endif
void init_execution_context (void)
{
register int i;
obj_init ();
merr_clear ();
codptr = code;
code[0] = EOL; /* init code_pointer */
partition = calloc ((unsigned) (PSIZE + 2), 1);
if (partition == NULL) exit (2); /* could not allocate stuff... */
for (i = 0; i < MAXNO_OF_RBUF; i++) {
rbuf_flags[i].standard = standard;
}
for (i = 0; i < NESTLEVLS; i++) {
extr_types[i] = DT_STRING;
}
symlen = PSIZE;
s = &partition[PSIZE] - 256; /* pointer to symlen_offset */
argptr = partition; /* pointer to beg of tmp-storage */
svntable = calloc ((unsigned) (UDFSVSIZ + 1), 1);
if (svntable == NULL) exit (2); /* could not allocate stuff... */
svnlen = UDFSVSIZ; /* begin of udf_svn_table */
buff = calloc ((unsigned) NO_OF_RBUF * (unsigned) PSIZE0, 1); /* routine buffer pool */
if (buff == NULL) exit (2); /* could not allocate stuff... */
newstack = calloc ((unsigned) NSIZE, 1);
if (newstack == NULL) exit (2); /* could not allocate stuff... */
#ifdef DEBUG_NEWPTR
printf("Allocating newptr stack...\r\n");
#endif
newptr = newstack;
newlimit = newstack + NSIZE - 1024;
namstck = calloc ((unsigned) NESTLEVLS * 13, 1);
if (namstck == NULL) exit (2); /* could not allocate stuff... */
*namstck = EOL;
*(namstck + 1) = EOL;
namptr = namstck; /* routine name stack pointer */
framstck = calloc ((unsigned) NESTLEVLS * 256, 1);
if (framstck == NULL) exit (2); /* could not allocate stuff... */
*framstck = EOL;
*(framstck + 1) = EOL;
dofrmptr = framstck; /* DO_frame stack pointer */
cmdstack = calloc ((unsigned) NESTLEVLS * 256, 1);
if (cmdstack == NULL) exit (2); /* could not allocate stuff... */
cmdptr = cmdstack; /* command stack */
rouend = rouins = rouptr = buff;
roucur = buff + (NO_OF_RBUF * PSIZE0 + 1);
*rouptr = EOL;
*(rouptr + 1) = EOL;
*(rouptr + 2) = EOL;
err_suppl[0] = EOL; /* empty out supplemental error info */
}
void init_estack (void)
{
stcpy (merr_stack[0].PLACE, "xecline()\201");
}
#if defined(HAVE_MWAPI_MOTIF)
void init_mwapi (void)
{
/*
if (getenv("DISPLAY") != NULL) {
gtk_init (0, NULL);
}
*/
//TODO: init Motif/libXt
}
#else
void init_mwapi (void)
{
return;
}
#endif
void init_io (void)
{
register int i;
/* initialize screen */
setbuf (stdin, NULL); /* no input buffering */
glvnflag.all = 0L;
stcpy (buff, "\201");
writeHOME (buff);
sq_modes[0] = '+';
for (i = 0; i <= MAXDEV; ug_buf[i++][0] = EOL); /* init read-buffers */
frm_crlf[HOME] = frm_filter;
if (hardcopy) zbreakon = ENABLE; /* enable CTRL/B */
set_io (MUMPS); /* set i/o parameters */
#if !defined(__AMIGA) && !defined(__OS2__)
if (ttyname (HOME)) { /* for $IO of HOME */
strcpy (dev[HOME], ttyname (HOME));
dev[HOME][strlen (dev[HOME])] = EOL;
}
else {
dev[HOME][0] = EOL; /* ...we are in a pipe */
}
#else
#if defined(__AMIGA)
strcpy (dev[HOME], "CONSOLE:");
#else
#if defined(__OS2__)
strcpy (dev[HOME], "CON:");
#endif
#endif
#endif
/* init function keys */
for (i = 0; i < 44; zfunkey[i++][0] = EOL);
}
void init_random_number (void)
{
srand (time (NULL));
if ((nrandom = time (0L) * getpid ()) < 0) {
nrandom = (-nrandom);
}
}
void init_ztrap (void)
{
if (frm_filter) {
ztrap[0][0] = EOL; /* no default ztrap for filters */
}
else if (startuprou[0] == '^') {
stcpy (ztrap[0], startuprou);
}
else {
stcpy (ztrap[0], "^%SYSINIT\201");
}
/* $ZT to be xecuted on startup */
stcpy (ztrap[NESTLEVLS + 1], ztrap[0]); /* DSM V.2 error trapping */
}
void init_ssvn(void)
{
ssvn_job_update ();
ssvn_display_update ();
ssvn_routine_update ();
ssvn_library_update ();
if (first_process) ssvn_system_update ();
}
void init_terminal(void)
{
xpos[HOME] = 80;
ypos[HOME] = 24;
}
void reset_terminal(void)
{
struct termio tpara;
ioctl (0, TCGETA, &tpara);
tpara.c_lflag |= (ECHO | ICANON); /* enable echo/no cbreak mode */
tpara.c_iflag |= ICRNL; /* cr-lf mapping */
tpara.c_oflag |= ONLCR; /* cr-lf mapping */
tpara.c_cc[VMIN] = EOT;
tpara.c_cc[VTIME] = -1;
ioctl (0, TCSETA, &tpara);
}
void cleanup (void)
{
char k_buf[256];
int ch;
/* remove this job's entry from ^$JOB SSVN */
snprintf (k_buf, 255, "^$JOB\202%d\201", pid);
symtab_shm (kill_sym, k_buf, " \201");
reset_terminal ();
if (tp_level > 0) {
if (direct_mode == TRUE) {
fprintf (stderr, "UNCOMMITTED TRANSACTIONS EXIST:\n\n");
tp_tdump ();
set_io (UNIX);
fprintf (stderr, "\nWould you like to c)ommit or r)ollback the above transactions and their operations? ($TLEVEL = %d) ", tp_level);
for (;;) {
ch = fgetc (stdin);
if (ch == 'c' || ch == 'C') {
while (tp_level > 0) tp_tcommit ();
fprintf (stderr, "\n\nTransactions have been committed.\n");
break;
}
else if (ch == 'r' || ch == 'R') {
tp_trollback (tp_level);
fprintf (stderr, "\n\nTransactions have been rolled back.\n");
break;
}
else {
fprintf (stderr, "\n\nInvalid input '%c'. Must choose c)ommit or r)ollback.\n", ch);
}
}
}
else {
fprintf (stderr, "Uncommitted transactions exist. Rolling back.\n");
tp_trollback (tp_level);
}
}
#if defined(HAVE_LIBREADLINE)
write_history (history_file);
#endif
locktab_unlock_all ();
job_remove (pid);
shm_exit ();
if (run_daemon == TRUE) {
if (pid_fd != -1) {
lockf (pid_fd, F_ULOCK, 0);
close (pid_fd);
}
if (pid_file_path != NULL) {
unlink (pid_file_path);
}
}
free (buff); /* free previously allocated space */
free (svntable);
if (partition) free (partition);
if (apartition) free (apartition);
free (newstack);
if (v22size) free (v22ali);
return;
} /* end of cleanup */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>