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>