Annotation of freem/src/mumps.c, revision 1.1
1.1 ! snw 1: /*
! 2: * *
! 3: * * *
! 4: * * *
! 5: * ***************
! 6: * * * * *
! 7: * * MUMPS *
! 8: * * * * *
! 9: * ***************
! 10: * * *
! 11: * * *
! 12: * *
! 13: *
! 14: * mumps.c
! 15: * main module of freem
! 16: *
! 17: *
! 18: * Author: Serena Willis <jpw@coherent-logic.com>
! 19: * Copyright (C) 1998 MUG Deutschland
! 20: * Copyright (C) 2020 Coherent Logic Development LLC
! 21: *
! 22: *
! 23: * This file is part of FreeM.
! 24: *
! 25: * FreeM is free software: you can redistribute it and/or modify
! 26: * it under the terms of the GNU Affero Public License as published by
! 27: * the Free Software Foundation, either version 3 of the License, or
! 28: * (at your option) any later version.
! 29: *
! 30: * FreeM is distributed in the hope that it will be useful,
! 31: * but WITHOUT ANY WARRANTY; without even the implied warranty of
! 32: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 33: * GNU Affero Public License for more details.
! 34: *
! 35: * You should have received a copy of the GNU Affero Public License
! 36: * along with FreeM. If not, see <https://www.gnu.org/licenses/>.
! 37: *
! 38: **/
! 39:
! 40: #include <stdlib.h>
! 41: #include <stddef.h>
! 42: #include "mpsdef.h"
! 43: #include "errmsg.h"
! 44: #include "iniconf.h"
! 45: #include "namespace.h"
! 46: #include "transact.h"
! 47: #include "init.h"
! 48: #include "consttbl.h"
! 49: #include <setjmp.h>
! 50: #include <stdio.h>
! 51: #include <signal.h>
! 52: #include <time.h>
! 53: #include <unistd.h>
! 54: #include <sys/types.h>
! 55: #include <sys/wait.h>
! 56: #include <sys/stat.h>
! 57: #include <limits.h>
! 58: #include <sys/types.h>
! 59: #include <pwd.h>
! 60: #include <string.h>
! 61: #include <fcntl.h>
! 62: #include "version.h"
! 63: #include "shmmgr.h"
! 64: #include "jobtab.h"
! 65: #include <errno.h>
! 66: #include <pwd.h>
! 67: #include <grp.h>
! 68:
! 69:
! 70: #if defined(HAVE_GETOPT_H)
! 71: # include <getopt.h>
! 72: #endif
! 73:
! 74: #if !defined(PATH_MAX) && defined(_SCO_DS)
! 75: # define PATH_MAX 1024
! 76: #endif
! 77:
! 78: extern int xecline(int typ);
! 79: extern char *getenv(const char *name);
! 80: void freem_usage(void);
! 81: void freem_print_version(void);
! 82: void init_ztrap(void);
! 83: void m_log (int, const char *);
! 84:
! 85: int main (int argc, char **argv, char **envp)
! 86: {
! 87: pid_t fork_pid = 0;
! 88: short dx_mode = 0;
! 89:
! 90: int c;
! 91: int import_env = FALSE;
! 92: short skip_init = 0;
! 93:
! 94: int option_index = 0;
! 95:
! 96: char dx_mcode[512];
! 97: char startup_routine[256];
! 98: short routine_mode;
! 99: char m_dialect[50];
! 100:
! 101: char nsnbuf[256];
! 102:
! 103: char d_username[40];
! 104: char d_groupname[40];
! 105: struct group *d_grp;
! 106: struct passwd *d_user;
! 107: gid_t d_gid;
! 108: uid_t d_uid;
! 109:
! 110: short custom_user = FALSE;
! 111: short custom_group = FALSE;
! 112:
! 113: #if defined(HAVE_GETOPT_LONG)
! 114: struct option long_options[] = {
! 115: {"help", no_argument, 0, 'h'},
! 116: {"filter", no_argument, &frm_filter, TRUE},
! 117: {"standard", required_argument, 0, 's'},
! 118: {"import", no_argument, &import_env, TRUE},
! 119: {"quiet", no_argument, &quiet_mode, TRUE},
! 120: {"restricted", no_argument, &restricted_mode, TRUE},
! 121: {"routine", required_argument, 0, 'r'},
! 122: {"namespace", required_argument, 0, 'n'},
! 123: {"environment", required_argument, 0, 'e'},
! 124: {"version", no_argument, 0, 'v'},
! 125: {"execute", required_argument, 0, 'x'},
! 126: {"daemon", no_argument, 0, 'd'},
! 127: {"nofork", no_argument, 0, 'k'},
! 128: {"pidfile", required_argument, 0, 'p'},
! 129: {"shmsize", required_argument, 0, 'S'},
! 130: {"user", required_argument, 0, 'u'},
! 131: {"group", required_argument, 0, 'g'},
! 132: {0, 0, 0, 0}
! 133: };
! 134: #endif
! 135:
! 136: char **env;
! 137: char *varname = (char *) calloc(STRLEN, sizeof(char));
! 138: char *varval = (char *) calloc(STRLEN, sizeof(char));
! 139:
! 140: char *symname = (char *) calloc(STRLEN, sizeof(char));
! 141: char *symval = (char *) calloc(STRLEN, sizeof(char));
! 142:
! 143: int namelen;
! 144: int vallen;
! 145:
! 146: char cli_rtn_path[PATH_MAX] = {0};
! 147: char *cli_rtn_file;
! 148: char cli_rtn_name[256];
! 149:
! 150: routine_mode = FALSE;
! 151: strcpy (m_dialect, "FREEM");
! 152:
! 153: m_argc = argc; /* save arguments count */
! 154: m_argv = argv; /* save arguments string */
! 155: m_envp = envp; /* save environment pointer */
! 156:
! 157: strncpy (shm_env, "DEFAULT", 8); /* establish default environment name */
! 158:
! 159: strncpy (d_username, "freem", 40);
! 160: strncpy (d_groupname, "freem", 40);
! 161:
! 162: strcpy (zb, argv[0]); /* name with which mumps has been called */
! 163: stcnv_c2m (zb);
! 164: strcpy (stack0, argv[0]);
! 165: stcnv_c2m (stack0);
! 166:
! 167:
! 168: /* strncpy (config_file, SYSCONFDIR"/freem.conf", 100); */
! 169:
! 170:
! 171:
! 172: #if defined(HAVE_GETOPT_LONG)
! 173:
! 174: extern char *optarg;
! 175: extern int optind, optopt;
! 176:
! 177: while (1) {
! 178:
! 179: c = getopt_long (argc, argv, "hsfiqRr:n:e:vx:dkpS:u:g:", long_options, &option_index);
! 180:
! 181: if (c == -1) break;
! 182: if (c == '?') freem_usage ();
! 183:
! 184: switch (c) {
! 185: case 'h':
! 186: freem_usage ();
! 187: break;
! 188:
! 189: case 'f':
! 190: frm_filter = TRUE;
! 191: break;
! 192:
! 193: case 'i':
! 194: import_env = TRUE;
! 195: break;
! 196:
! 197: case 'q':
! 198: quiet_mode = TRUE;
! 199: break;
! 200:
! 201: case 'e': /* specify FreeM environment */
! 202: strncpy (shm_env, optarg, 255);
! 203: break;
! 204:
! 205: case 'R':
! 206: restricted_mode = TRUE;
! 207: break;
! 208:
! 209: case 'r': /* startup routine */
! 210: direct_mode = FALSE;
! 211: usermode = 0;
! 212:
! 213: strcpy (startup_routine, optarg);
! 214: startup_routine[strlen (startup_routine)] = '\201';
! 215:
! 216: routine_mode = TRUE;
! 217: break;
! 218:
! 219: case 'n': /* namespace */
! 220: {
! 221: if (validate_namespace (optarg) == TRUE) {
! 222: strcpy (nsname, optarg);
! 223: }
! 224: else {
! 225: fprintf (stderr, "freem: invalid namespace '%s'\n", optarg);
! 226: exit (1);
! 227: }
! 228:
! 229: break;
! 230: }
! 231: case 'v': /* version */
! 232: freem_print_version ();
! 233: break;
! 234:
! 235: case 'x': /* execute */
! 236: direct_mode = FALSE;
! 237: usermode = 0;
! 238: dx_mode = 1;
! 239:
! 240: strncpy (dx_mcode, optarg, 512 - 1);
! 241:
! 242: stcnv_c2m (dx_mcode);
! 243:
! 244: break;
! 245:
! 246: case 's': /* --standard */
! 247:
! 248: if (strcmp (optarg, "M77") == 0) {
! 249: standard = D_M77;
! 250: strcpy (m_dialect, "M 1977");
! 251: }
! 252: else if (strcmp (optarg, "M84") == 0) {
! 253: standard = D_M84;
! 254: strcpy (m_dialect, "M 1984");
! 255: }
! 256: else if (strcmp (optarg, "M90") == 0) {
! 257: standard = D_M90;
! 258: strcpy (m_dialect, "M 1990");
! 259: }
! 260: else if (strcmp (optarg, "M95") == 0) {
! 261: standard = D_M95;
! 262: strcpy (m_dialect, "M 1995");
! 263: }
! 264: else if (strcmp (optarg, "MDS") == 0) {
! 265: standard = D_MDS;
! 266: strcpy (m_dialect, "Millennium Draft Standard");
! 267: }
! 268: else if (strcmp (optarg, "M5") == 0) {
! 269: standard = D_M5;
! 270: strcpy (m_dialect, "M5");
! 271: }
! 272: else if (strcmp (optarg, "FREEM") == 0) {
! 273: standard = D_FREEM;
! 274: strcpy (m_dialect, "FREEM");
! 275: }
! 276: else {
! 277: freem_usage ();
! 278: }
! 279:
! 280: break;
! 281:
! 282: case 'd': /* --daemon */
! 283: run_daemon = TRUE;
! 284: break;
! 285:
! 286: case 'k': /* --nofork */
! 287: nofork = TRUE;
! 288: break;
! 289:
! 290: case 'p': /* --pidfile */
! 291: pid_file_path = strdup (optarg);
! 292: break;
! 293:
! 294: case 'S': /* --shmsize */
! 295: shm_init_size = atol (optarg);
! 296: break;
! 297:
! 298: case 'u': /* --user */
! 299: strncpy (d_username, optarg, 40);
! 300: custom_user = TRUE;
! 301: break;
! 302:
! 303: case 'g': /* --group */
! 304: strncpy (d_groupname, optarg, 40);
! 305: custom_group = TRUE;
! 306: break;
! 307:
! 308:
! 309: }
! 310:
! 311: }
! 312:
! 313: #else
! 314:
! 315: {
! 316: extern char *optarg;
! 317: extern int optind, optopt;
! 318:
! 319: while ((c = getopt (argc, argv, "hsfiqRr:n:e:vx:dkpS:u:g:")) != -1) {
! 320:
! 321: if (c == '?') freem_usage ();
! 322:
! 323: switch (c) {
! 324:
! 325: case 'h':
! 326: freem_usage ();
! 327: break;
! 328:
! 329: case 'f':
! 330: frm_filter = TRUE;
! 331: break;
! 332:
! 333: case 'i':
! 334: import_env = TRUE;
! 335: break;
! 336:
! 337: case 'q':
! 338: quiet_mode = TRUE;
! 339: break;
! 340:
! 341: case 'e': /* specify FreeM environment */
! 342: strncpy (shm_env, optarg, 255);
! 343: break;
! 344:
! 345: case 'R':
! 346: restricted_mode = TRUE;
! 347: break;
! 348:
! 349: case 'r': /* startup routine */
! 350: direct_mode = FALSE;
! 351: usermode = 0;
! 352:
! 353: strcpy (startup_routine, optarg);
! 354: startup_routine[strlen (startup_routine)] = '\201';
! 355:
! 356: routine_mode = TRUE;
! 357: break;
! 358:
! 359: case 'n': /* namespace */
! 360: strcpy (nsname, optarg);
! 361: break;
! 362:
! 363: case 'v':
! 364: freem_print_version ();
! 365: break;
! 366:
! 367: case 'x': /* execute */
! 368: direct_mode = FALSE;
! 369: usermode = 0;
! 370: dx_mode = 1;
! 371:
! 372: strncpy (dx_mcode, optarg, 512 - 1);
! 373:
! 374: stcnv_c2m (dx_mcode);
! 375:
! 376: break;
! 377:
! 378: case 'd': /* --daemon */
! 379: run_daemon = TRUE;
! 380: break;
! 381:
! 382: case 'k': /* --nofork */
! 383: nofork = TRUE;
! 384: break;
! 385:
! 386: case 'p': /* --pidfile */
! 387: pid_file_path = strdup (optarg);
! 388: break;
! 389:
! 390: case 's': /* --standard */
! 391:
! 392: if (strcmp (optarg, "M77") == 0) {
! 393: standard = D_M77;
! 394: strcpy (m_dialect, "M 1977");
! 395: }
! 396: else if (strcmp (optarg, "M84") == 0) {
! 397: standard = D_M84;
! 398: strcpy (m_dialect, "M 1984");
! 399: }
! 400: else if (strcmp (optarg, "M90") == 0) {
! 401: standard = D_M90;
! 402: strcpy (m_dialect, "M 1990");
! 403: }
! 404: else if (strcmp (optarg, "M95") == 0) {
! 405: standard = D_M95;
! 406: strcpy (m_dialect, "M 1995");
! 407: }
! 408: else if (strcmp (optarg, "MDS") == 0) {
! 409: standard = D_MDS;
! 410: strcpy (m_dialect, "Millennium Draft Standard");
! 411: }
! 412: else if (strcmp (optarg, "M5") == 0) {
! 413: standard = D_M5;
! 414: strcpy (m_dialect, "M5");
! 415: }
! 416: else if (strcmp (optarg, "FREEM") == 0) {
! 417: standard = D_FREEM;
! 418: strcpy (m_dialect, "FREEM");
! 419: }
! 420: else {
! 421: freem_usage ();
! 422: }
! 423:
! 424: break;
! 425:
! 426:
! 427: case 'S': /* --shmsize */
! 428: shm_init_size = atol (optarg);
! 429: break;
! 430:
! 431: case 'u': /* --user */
! 432: strncpy (d_username, optarg, 40);
! 433: custom_user = TRUE;
! 434: break;
! 435:
! 436: case 'g': /* --group */
! 437: strncpy (d_groupname, optarg, 40);
! 438: custom_group = TRUE;
! 439: break;
! 440:
! 441:
! 442: }
! 443: }
! 444: }
! 445: #endif
! 446: snprintf (config_file, 4096, "%s/freem/%s/freem.conf", SYSCONFDIR, shm_env);
! 447:
! 448: if (run_daemon == TRUE && geteuid() == 0) {
! 449:
! 450: if (custom_group) {
! 451: d_grp = getgrnam (d_groupname);
! 452:
! 453: if (d_grp == NULL) {
! 454: fprintf (stderr, "freem: invalid group '%s'\n", d_groupname);
! 455: exit (1);
! 456: }
! 457:
! 458: d_gid = d_grp->gr_gid;
! 459: }
! 460:
! 461: if (custom_user) {
! 462: d_user = getpwnam (d_username);
! 463:
! 464: if (d_user == NULL) {
! 465: fprintf (stderr, "freem: invalid user '%s'\n", d_username);
! 466: exit (1);
! 467: }
! 468:
! 469: d_uid = d_user->pw_uid;
! 470: }
! 471:
! 472: }
! 473:
! 474: if ((nofork == TRUE) && (run_daemon == FALSE)) {
! 475: freem_usage ();
! 476: exit (1);
! 477: }
! 478:
! 479: if ((run_daemon == TRUE) && (nofork == FALSE)) {
! 480:
! 481: int fork_fd;
! 482:
! 483: /* daemonize */
! 484:
! 485: fork_pid = fork ();
! 486:
! 487: if (fork_pid < 0) {
! 488: fprintf (stderr, "freem: failure in fork()\r\n");
! 489: m_log (1, "failure in initial fork()\r\n");
! 490: exit (1);
! 491: }
! 492:
! 493: if (fork_pid > 0) {
! 494: exit (0);
! 495: }
! 496:
! 497: if (setsid () < 0) {
! 498: fprintf (stderr, "freem: failure in setsid()\r\n");
! 499: m_log (1, "failure in setsid()\r\n");
! 500: exit (1);
! 501: }
! 502:
! 503: signal (SIGCHLD, SIG_IGN);
! 504:
! 505: fork_pid = fork ();
! 506:
! 507: if (fork_pid < 0) {
! 508: fprintf (stderr, "freem: failure in fork()\r\n");
! 509: m_log (1, "failure in second fork()\r\n");
! 510: exit (1);
! 511: }
! 512:
! 513: if (fork_pid > 0) {
! 514: exit (0);
! 515: m_log (1, "exiting from second fork");
! 516: }
! 517:
! 518: umask (0);
! 519:
! 520: chdir ("/");
! 521:
! 522: for (fork_fd = sysconf (_SC_OPEN_MAX); fork_fd > 0; fork_fd--) {
! 523: close (fork_fd);
! 524: }
! 525:
! 526: if (geteuid () == 0) {
! 527: /* shed privileges */
! 528:
! 529: if (custom_group) {
! 530: fprintf (stderr, "freem: switching to group %s\n", d_groupname);
! 531: m_log (1, "switching groups");
! 532:
! 533: if (setgid (d_gid) == -1) {
! 534: fprintf (stderr, "freem: failure switching GID\n");
! 535: m_log (1, "failure switching GIDs");
! 536: exit (1);
! 537: }
! 538: }
! 539:
! 540:
! 541: if (custom_user) {
! 542: fprintf (stderr, "freem: switching to username %s\n", d_username);
! 543: m_log (1, "switching users");
! 544:
! 545: if (setuid (d_uid) == -1) {
! 546: fprintf (stderr, "freem: failure switching UID\n");
! 547: m_log (1, "failure switching UIDs");
! 548: exit (1);
! 549: }
! 550: if (chdir (d_user->pw_dir) == -1) {
! 551: fprintf (stderr, "freem: chdir failure\n");
! 552: m_log (1, "failure in chdir");
! 553: exit (1);
! 554: }
! 555: }
! 556:
! 557: }
! 558: else {
! 559: fprintf (stderr, "not euid 0");
! 560: }
! 561:
! 562: freopen ("/dev/null", "r", stdin);
! 563: freopen ("/dev/null", "w+", stdout);
! 564: freopen ("/dev/null", "w+", stderr);
! 565:
! 566: run_daemon = TRUE;
! 567: nofork = FALSE;
! 568:
! 569: if (pid_file_path == NULL) {
! 570: /* no PID file specified. choose one. */
! 571: uid_t pid_uid;
! 572: char *home_directory;
! 573:
! 574: pid_file_path = (char *) calloc (PATH_MAX, sizeof (char));
! 575: NULLPTRCHK(pid_file_path,"main");
! 576:
! 577: home_directory = (char *) calloc (PATH_MAX, sizeof (char));
! 578: NULLPTRCHK(home_directory,"main");
! 579:
! 580: pid_uid = geteuid ();
! 581:
! 582: if (pid_uid == 0) {
! 583: /* we're running as root */
! 584: strcpy (pid_file_path, "/var/run/freem.pid");
! 585: }
! 586: else {
! 587: /* our user is a normie */
! 588: struct passwd *pw = getpwuid (pid_uid);
! 589:
! 590: if (pw == NULL) {
! 591: m_log (1, "main: failure in getpwuid()");
! 592: }
! 593:
! 594: strcpy (home_directory, pw->pw_dir);
! 595: snprintf (pid_file_path, PATH_MAX - 1, "%s/.freem.pid", home_directory);
! 596: }
! 597:
! 598: free (home_directory);
! 599:
! 600: }
! 601:
! 602: {
! 603: char pidfile_buf[256];
! 604: int errsav;
! 605:
! 606: m_log (1, pid_file_path);
! 607:
! 608: pid_fd = open (pid_file_path, O_RDWR | O_CREAT, 0640);
! 609: errsav = errno;
! 610:
! 611: if (pid_fd < 0) {
! 612: m_log (1, "freem: could not open PID file");
! 613: m_log (1, strerror (errsav));
! 614: exit (1);
! 615: }
! 616:
! 617: if (lockf (pid_fd, F_TLOCK, 0) < 0) {
! 618: errsav = errno;
! 619: m_log (1, "freem: could not lock PID file - perhaps already running?");
! 620: m_log (1, strerror (errsav));
! 621: exit (1);
! 622: }
! 623:
! 624: sprintf (pidfile_buf, "%d\n", getpid ());
! 625: write (pid_fd, pidfile_buf, strlen (pidfile_buf));
! 626:
! 627: }
! 628:
! 629:
! 630: } /* END of daemonization */
! 631:
! 632: /* handle passing of an arbitrary .m file on the command line */
! 633: /* this is most often used for shebang-line scripts. */
! 634: if (optind < argc) {
! 635:
! 636: /* not valid for daemon mode */
! 637: if (run_daemon == TRUE) {
! 638: fprintf (stderr, "freem: cannot pass --daemon flag in shebang line\r\n");
! 639: exit (1);
! 640: }
! 641:
! 642: /* bail if file does not exist */
! 643: if (access (argv[optind], F_OK) == -1) {
! 644:
! 645: set_io (UNIX);
! 646:
! 647: fprintf (stderr, "Routine %s does not exist.\n", argv[optind]);
! 648:
! 649: exit (1);
! 650:
! 651: }
! 652:
! 653: skip_init = 1;
! 654:
! 655: /* initialize FreeM environment */
! 656: strncpy (nsnbuf, nsname, 255);
! 657: if (init (nsnbuf) == FALSE) {
! 658:
! 659: set_io (UNIX);
! 660: fprintf (stderr, "\nError initializing FreeM.\n");
! 661:
! 662: exit (1);
! 663:
! 664: }
! 665:
! 666:
! 667: direct_mode = FALSE;
! 668: usermode = 0;
! 669:
! 670: /* was a path specified at all? */
! 671: if (strchr (argv[optind], '/') == NULL) {
! 672:
! 673: /* the entirety of argv[optind] is the filename */
! 674: cli_rtn_file = argv[optind];
! 675:
! 676: /* use the current directory */
! 677: sprintf (cli_rtn_path, ".");
! 678:
! 679: }
! 680: else {
! 681:
! 682: /* isolate the filename from the path */
! 683: cli_rtn_file = strrchr (argv[optind], '/') + 1;
! 684:
! 685: /* isolate the routine name from the filename */
! 686: strncpy (cli_rtn_name, cli_rtn_file, strchr (cli_rtn_file, '.') - cli_rtn_file);
! 687:
! 688: /* isolate the path from the routine file */
! 689: strncpy (cli_rtn_path, argv[optind], strrchr (argv[optind], '/') - argv[optind]);
! 690:
! 691: /* set_io (UNIX);
! 692: printf ("cli_rtn_name = '%s' cli_rtn_path = '%s'\n", cli_rtn_name, cli_rtn_path);
! 693: set_io (MUMPS);
! 694: */
! 695: }
! 696:
! 697: /* do we have a file extension? */
! 698: if (strchr (cli_rtn_file, '.') != NULL) {
! 699:
! 700: /* if so, just remove it */
! 701: strncpy (cli_rtn_name, cli_rtn_file, strchr (cli_rtn_file, '.') - cli_rtn_file);
! 702:
! 703: }
! 704: else {
! 705:
! 706: /* otherwise, just take a direct copy */
! 707: strcpy (cli_rtn_name, cli_rtn_file);
! 708:
! 709: }
! 710:
! 711: /* make this the startup routine */
! 712: snprintf (startuprou, 256, "^%s\201", cli_rtn_name);
! 713:
! 714: /* re-work the namespace config to search for the
! 715: routine in the discovered path */
! 716: if (cli_rtn_name[0] == '%') {
! 717:
! 718: snprintf (rou0plib, 256, "%s\201", cli_rtn_path);
! 719: snprintf (rou1plib, 256, "%s\201", cli_rtn_path);
! 720:
! 721: }
! 722: else {
! 723:
! 724: snprintf (rou0path, 256, "%s\201", cli_rtn_path);
! 725: snprintf (rou1path, 256, "%s\201", cli_rtn_path);
! 726:
! 727: }
! 728:
! 729: }
! 730:
! 731:
! 732: if (!file_exists (config_file)) {
! 733:
! 734: set_io (UNIX);
! 735: fprintf (stderr, "\nFreeM has not been configured. Please run 'fmadm configure'.\n\n\n\n");
! 736:
! 737: exit (2);
! 738:
! 739: }
! 740:
! 741: if (!skip_init) {
! 742: /* initialize FreeM environment */
! 743: strncpy (nsnbuf, nsname, 255);
! 744: if (init (nsnbuf) == FALSE) {
! 745:
! 746: set_io (UNIX);
! 747: fprintf (stderr, "\nError initializing FreeM.\n");
! 748:
! 749: exit (1);
! 750:
! 751: }
! 752: }
! 753:
! 754: if (first_process == TRUE) {
! 755:
! 756: char verstr[500];
! 757: pid_t stop_requester;
! 758:
! 759: if (run_daemon == FALSE) {
! 760: fprintf (stderr, "freem: re-run with --daemon or -d command-line flags\r\n");
! 761: cleanup ();
! 762: exit (1);
! 763: }
! 764:
! 765: stcpy (verstr, FREEM_VERSION_STR);
! 766: stcnv_m2c (verstr);
! 767:
! 768: fprintf (stderr, "Coherent Logic Development FreeM version %s\r\n", verstr);
! 769: fprintf (stderr, "freem: shared memory for environment %s initialized (%d bytes of shared memory @ '%p')\r\nfreem: system ready\r\n", shm_env, shm_init_size, shm_config->dta);
! 770:
! 771: for (;;) {
! 772:
! 773: job_set_status (pid, JSTAT_HOUSEKEEPING);
! 774:
! 775:
! 776: if (shm_config->hdr->maintenance_mode == 1) {
! 777:
! 778: job_slot_t *slot;
! 779:
! 780: fprintf (stderr, "freem: entering maintenance mode\r\n");
! 781: m_log (1, "freem: entering maintenance mode");
! 782:
! 783: for (slot = shm_config->hdr->jobtab_head; slot != NULL; slot = slot->next) {
! 784:
! 785: if ((slot->pid != pid) && ((slot->flags & JFLG_FMADM) != JFLG_FMADM)) {
! 786: kill (slot->pid, SIGINT);
! 787: }
! 788:
! 789: }
! 790:
! 791: }
! 792:
! 793: if ((stop_requester = job_stop_requested (pid)) != 0) {
! 794: int connected_jobs;
! 795:
! 796: job_set_status (pid, JSTAT_SHUTDOWN);
! 797:
! 798: connected_jobs = job_count ();
! 799:
! 800: fprintf (stderr, "freem: STOP requested by pid %d\r\n", stop_requester);
! 801: fprintf (stderr, "freem: there are %d job(s) connected to this environment\r\n", connected_jobs);
! 802:
! 803: if (connected_jobs > 1) {
! 804:
! 805: fprintf (stderr, "freem: asking non-daemon job(s) to disconnect and halt...\r\n");
! 806: job_request_all_stop ();
! 807:
! 808: fprintf (stderr, "freem: waiting 5 seconds for job(s) to disconnect...\r\n");
! 809: sleep (5);
! 810:
! 811: connected_jobs = job_count ();
! 812: if (connected_jobs > 1) {
! 813: fprintf (stderr, "freem: sending SIGTERM to %d job(s)...\r\n", connected_jobs);
! 814: job_signal_all (SIGTERM);
! 815: fprintf (stderr, "freem: waiting 5 seconds for job(s) to disconnect...\r\n");
! 816:
! 817: sleep (5);
! 818: }
! 819:
! 820: connected_jobs = job_count ();
! 821: if (connected_jobs > 1) {
! 822: fprintf (stderr, "freem: sending SIGKILL to %d job(s)...\r\n", connected_jobs);
! 823: job_signal_all (SIGKILL);
! 824: }
! 825:
! 826: job_gc_mark ();
! 827: job_gc_sweep ();
! 828:
! 829: }
! 830:
! 831: fprintf (stderr, "freem: terminating\r\n");
! 832: cleanup ();
! 833: exit (0);
! 834:
! 835: }
! 836:
! 837: job_gc_mark ();
! 838: job_set_status (pid, JSTAT_IDLE);
! 839: sleep (1);
! 840:
! 841: job_set_status (pid, JSTAT_HOUSEKEEPING);
! 842: job_gc_sweep ();
! 843: sleep (1);
! 844: }
! 845:
! 846: }
! 847:
! 848:
! 849: #if !defined(_AIX)
! 850: if(import_env == TRUE) {
! 851:
! 852: int i_maxlen = 255;
! 853:
! 854: for(env = envp; *env != 0; env++) {
! 855:
! 856: namelen = 0;
! 857: vallen = 0;
! 858:
! 859: varname = strtok(*env, "=");
! 860: varval = strtok(NULL, "=");
! 861:
! 862: if(varval != NULL) {
! 863: namelen = strlen (varname);
! 864: vallen = strlen (varval);
! 865:
! 866: snprintf (symname, i_maxlen, "ENV.%s\201\201", varname);
! 867: strncpy (symval, varval, i_maxlen);
! 868:
! 869: stcnv_c2m (symval);
! 870:
! 871: symtab (set_sym, symname, symval);
! 872: }
! 873: }
! 874: }
! 875: #endif
! 876:
! 877:
! 878: if (direct_mode == TRUE && quiet_mode == FALSE) {
! 879:
! 880: char verstr[500];
! 881: char version[256];
! 882:
! 883: stcpy (verstr, FREEM_VERSION_STR);
! 884: stcnv_m2c (verstr);
! 885:
! 886: snprintf (version, 255, "\r\nCoherent Logic Development FreeM version %s [DIALECT: %s%s]\r\n\201", verstr, m_dialect, (restricted_mode == TRUE ? "/RESTRICTED" : ""));
! 887: write_m (version);
! 888:
! 889: snprintf (version, 255, "Copyright (C) 2014, 2020, 2021, 2023 Coherent Logic Development LLC\r\n\r\n\201");
! 890: write_m (version);
! 891:
! 892: printf ("Environment: \t%s\r\n", shm_env);
! 893: printf ("Environment Daemon:\tPID %d\r\n", shm_config->hdr->first_process);
! 894: printf ("Interpreter Process:\tPID %d\r\n", pid);
! 895:
! 896:
! 897: }
! 898: else {
! 899: write_m ("\r\n\r\n\201");
! 900: }
! 901:
! 902: if (dx_mode) {
! 903: char k_buf[512];
! 904:
! 905: snprintf (k_buf, 512 - 1, "%%TMPINITMCODE\201\201");
! 906: symtab (set_sym, k_buf, dx_mcode);
! 907: const_define (k_buf, dx_mcode);
! 908: }
! 909:
! 910: if (routine_mode) {
! 911: char k_buf[512];
! 912:
! 913: snprintf (k_buf, 512 - 1, "%%TMPINITROUTINE\201\201");
! 914: symtab (set_sym, k_buf, startup_routine);
! 915: const_define (k_buf, startup_routine);
! 916: }
! 917:
! 918: /* run mumps */
! 919: xecline (1);
! 920:
! 921: exit (0); /* we should never reach that statement */
! 922:
! 923: } /* end of main() */
! 924:
! 925: void freem_usage(void)
! 926: {
! 927: fprintf (stdout, "\nusage: freem [OPTION...]\n\n");
! 928:
! 929: fprintf (stdout, "OPTIONS:\n\n");
! 930:
! 931: #if defined(HAVE_GETOPT_LONG)
! 932: fprintf (stdout, "\t-h, --help\n\t\tdisplays this help message\n\n");
! 933: fprintf (stdout, "\t-i, --import\n\t\timports UNIX environment variables as M locals\n\n");
! 934: fprintf (stdout, "\t-e <environment-name>, --environment=<environment-name>\n\t\tsets active environment to <environment-name> (DEFAULT if unspecified)\n\n");
! 935: fprintf (stdout, "\t-f, --filter\n\t\tallows M code to be used as a filter\n\n");
! 936: fprintf (stdout, "\t-n <NAMESPACE>, --namespace=<NAMESPACE>\n\t\tselects <NAMESPACE> as the startup namespace instead of USER\n\n");
! 937: fprintf (stdout, "\t-q, --quiet\n\t\tdisables startup messages and prompt string\n\n");
! 938: fprintf (stdout, "\t-r <LABEL^ROUTINE>, --routine=<LABEL^ROUTINE>\n\t\texecute <LABEL^ROUTINE> on startup instead of entering direct mode\n\n");
! 939: fprintf (stdout, "\t-s, --standard\n\t\trestrict access to FreeM vendor extensions not present in relevant standards*\n\n");
! 940: fprintf (stdout, "\t-v, --version\n\t\tdisplay FreeM version information\n\n");
! 941: fprintf (stdout, "\t-x <MCODE>, --execute=<MCODE>\n\t\texecute M code <MCODE> on startup\n\n");
! 942: fprintf (stdout, "\t-d, --daemon\n\t\trun the FreeM daemon (one and only one FreeM daemon must always be running)\n\n");
! 943: fprintf (stdout, "\t-k, --nofork\n\t\trun the FreeM daemon in foreground (requires --daemon)\n\n");
! 944: fprintf (stdout, "\t-p <PIDFILE>, --pidfile=<PIDFILE>\n\t\tuse <PIDFILE> to record the PID of the FreeM daemon\n\n\n");
! 945: fprintf (stdout, "\t-S <BYTES>, --shmsize=<BYTES>\n\t\tsets the size of the shared memory segment where FreeM stores the job table, lock table, and IPC table.\n");
! 946: #else
! 947: fprintf (stdout, "\t-h\n\t\tdisplays this help message\n\n");
! 948: fprintf (stdout, "\t-i\n\t\timports UNIX environment variables as M locals\n\n");
! 949: fprintf (stdout, "\t-e <environment-name>\n\t\tsets active environment to <environment-name> (DEFAULT if unspecified)\n\n");
! 950: fprintf (stdout, "\t-f\n\t\tallows M code to be used as a filter\n\n");
! 951: fprintf (stdout, "\t-n <NAMESPACE>\n\t\tselects <NAMESPACE> as the startup namespace instead of USER\n\n");
! 952: fprintf (stdout, "\t-q\n\t\tdisables startup messages and prompt string\n\n");
! 953: fprintf (stdout, "\t-r <LABEL^ROUTINE>\n\t\texecute <LABEL^ROUTINE> on startup instead of entering direct mode\n\n");
! 954: fprintf (stdout, "\t-s\n\t\trestrict access to FreeM vendor extensions not present in relevant standards*\n\n");
! 955: fprintf (stdout, "\t-v\n\t\tdisplay FreeM version information\n\n");
! 956: fprintf (stdout, "\t-x <MCODE>\n\t\texecute M code <MCODE> on startup\n\n");
! 957: fprintf (stdout, "\t-d\n\t\trun the FreeM daemon (one and only one FreeM daemon must always be running)\n\n");
! 958: fprintf (stdout, "\t-k\n\t\trun the FreeM daemon in foreground (requires --daemon)\n\n");
! 959: fprintf (stdout, "\t-p <PIDFILE>\n\t\tuse <PIDFILE> to record the PID of the FreeM daemon\n\n\n");
! 960: fprintf (stdout, "\t-S <BYTES>\n\t\tsets the size of the shared memory segment where FreeM stores the job table, lock table, and IPC table.\n");
! 961: #endif
! 962: fprintf (stdout, "\t\t - Each concurrent job takes %d bytes (1 page) of shared memory\n", PG_SIZE);
! 963: fprintf (stdout, "\t\t - Each LOCK takes %d bytes (2 pages) of shared memory\n", PG_SIZE * 2);
! 964: fprintf (stdout, "\t\t - Each IPC takes %d bytes (1 page) of shared memory\n\n", PG_SIZE);
! 965: fprintf (stdout, "\t* FreeM attempts to conform (at least loosely) to the Millennium Draft Standard when this mode is selected.\n\n\n");
! 966: fprintf (stdout, "Report bugs to: freem-bugs@coherent-logic.com\n");
! 967: fprintf (stdout, "FreeM home page: <https://freem.coherent-logic.com>\n\n");
! 968:
! 969: exit (1);
! 970: }
! 971:
! 972: void freem_print_version(void)
! 973: {
! 974: char verstr[500];
! 975: stcpy (verstr, FREEM_VERSION_STR);
! 976: stcnv_m2c (verstr);
! 977:
! 978: fprintf (stdout, "Coherent Logic Development FreeM %s\n", verstr);
! 979: fprintf (stdout, "Copyright (C) 2014, 2020, 2021, 2023 Coherent Logic Development LLC\n\n");
! 980: fprintf (stdout, "License AGPLv3+: GNU AGPL version 3 or later <https://gnu.org/license/agpl-3.0.html>\n");
! 981: fprintf (stdout, "This is free software: you are free to change and redistribute it.\n");
! 982: fprintf (stdout, "There is NO WARRANTY, to the extent permitted by law.\n");
! 983:
! 984: exit (0);
! 985: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>